Abstraction and Interfaces in Python
1. Introduction to Abstraction
What is Abstraction?
Abstraction is one of the four fundamental principles of Object-Oriented Programming (OOP), along with
Encapsulation, Inheritance, and Polymorphism.
Simple Definition: Abstraction means hiding the complex implementation details and showing only the
essential features of an object. It focuses on “what an object does” rather than “how it does it.”
Real-World Analogy
Think about driving a car:
What you see (Abstract): Steering wheel, pedals, gear shift
What you don’t see (Hidden): Engine mechanics, fuel injection system, transmission details
You know what each control does (steering wheel turns the car), but you don’t need to know how it works
internally (hydraulic systems, power steering mechanisms). That’s abstraction!
Another example - Your TV remote:
Abstract: Power button, volume buttons, channel buttons
Hidden: Infrared signals, circuit boards, signal processing
Why is Abstraction Important?
1. Simplifies Complexity - Users don’t need to understand complex internal workings
2. Increases Security - Hides sensitive implementation details
3. Reduces Code Duplication - Common interfaces for similar operations
4. Improves Maintainability - Implementation can change without affecting users
5. Provides Clear Structure - Defines what must be implemented
6. Enables Polymorphism - Different classes can implement the same interface
2. Understanding Abstraction in OOP
Levels of Abstraction
In programming, abstraction exists at multiple levels:
Level 1: Simple Functions
# User sees: Simple function call
result = calculate_average(numbers)
# Hidden: Complex implementation details
def calculate_average(numbers):
total = sum(numbers)
count = len(numbers)
return total / count if count > 0 else 0
Level 2: Classes
# User sees: Simple methods
account = BankAccount()
[Link](100)
[Link](50)
# Hidden: Internal balance management, validation, logging, etc.
Level 3: Abstract Classes and Interfaces
# User sees: What methods must exist
class Vehicle(ABC):
@abstractmethod
def start(self):
pass
# Hidden: Each vehicle implements start differently
Two Types of Abstraction
1. Data Abstraction
Hiding internal data and providing access through methods.
class BankAccount:
def __init__(self):
self.__balance = 0 # Hidden (private)
# Public interface
def deposit(self, amount):
self.__balance += amount
def get_balance(self):
return self.__balance
# Users interact through methods, not directly with __balance
2. Process Abstraction
Hiding implementation details of operations.
class EmailSender:
def send_email(self, to, subject, body):
# Complex implementation hidden
self._connect_to_server()
self._authenticate()
self._compose_message(to, subject, body)
self._send()
self._disconnect()
# Users only call send_email(), details are hidden
3. Abstract Classes in Python
What is an Abstract Class?
Abstract Class is a class that cannot be instantiated (you cannot create objects from it) and is designed to be
inherited by other classes. It serves as a blueprint or template for other classes.
Key Characteristics:
1. Cannot create instances directly
2. Contains one or more abstract methods
3. May also contain concrete (regular) methods
4. Must be inherited by child classes
5. Child classes must implement all abstract methods
Why Use Abstract Classes?
1. Define a Contract - Specify what methods child classes must implement
2. Enforce Standards - Ensure all child classes have required methods
3. Share Common Code - Provide common functionality in concrete methods
4. Prevent Instantiation - Force users to use specific implementations
5. Design Framework - Create frameworks where others fill in the details
Abstract Class vs Regular Class
# Regular Class - Can be instantiated
class Animal:
def speak(self):
print("Some sound")
animal = Animal() # This works fine
# Abstract Class - Cannot be instantiated
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
# animal = Animal() # This will raise TypeError!
4. The abc Module (Abstract Base Classes)
What is the abc Module?
The abc module (Abstract Base Classes) is Python’s built-in module for creating abstract classes. It provides
the infrastructure for defining abstract base classes.
ABC stands for Abstract Base Class.
Key Components of abc Module
1. ABC Class - Base class for creating abstract classes
2. abstractmethod Decorator - Marks methods as abstract
3. abstractproperty - For abstract properties (less common)
Importing the abc Module
from abc import ABC, abstractmethod
# Now you can create abstract classes
class MyAbstractClass(ABC):
@abstractmethod
def my_abstract_method(self):
pass
Two Ways to Create Abstract Classes
Method 1: Inherit from ABC (Recommended)
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
Method 2: Using ABCMeta as Metaclass
from abc import ABCMeta, abstractmethod
class Shape(metaclass=ABCMeta):
@abstractmethod
def area(self):
pass
Both methods work the same way. Method 1 is more common and easier to read.
5. Creating Abstract Classes
Basic Structure
from abc import ABC, abstractmethod
class AbstractClassName(ABC):
@abstractmethod
def abstract_method_name(self):
"""This method must be implemented by child classes"""
pass
def concrete_method(self):
"""This method has implementation and is inherited"""
print("This is a concrete method")
Example 1: Simple Abstract Class
from abc import ABC, abstractmethod
# Abstract class
class Animal(ABC):
def __init__(self, name):
[Link] = name
# Abstract method - must be implemented by child classes
@abstractmethod
def speak(self):
pass
# Concrete method - inherited by all child classes
def introduce(self):
print(f"I am {[Link]}")
# This will raise an error
# animal = Animal("Generic") # TypeError: Can't instantiate abstract class
# Child class must implement abstract methods
class Dog(Animal):
def speak(self):
return "Woof! Woof!"
class Cat(Animal):
def speak(self):
return "Meow! Meow!"
# Now we can create instances of child classes
dog = Dog("Buddy")
cat = Cat("Whiskers")
print("=== Dog ===")
[Link]() # Inherited from Animal
print([Link]()) # Implemented in Dog
print("\n=== Cat ===")
[Link]() # Inherited from Animal
print([Link]()) # Implemented in Cat
Output:
=== Dog ===
I am Buddy
Woof! Woof!
=== Cat ===
I am Whiskers
Meow! Meow!
Detailed Explanation:
1. Abstract Class Animal :
Inherits from ABC to make it abstract
Has one abstract method: speak()
Has one concrete method: introduce()
Cannot be instantiated directly
2. Abstract Method speak() :
Marked with @abstractmethod decorator
Has no implementation (just pass )
Must be implemented by all child classes
3. Concrete Method introduce() :
Has actual implementation
Inherited by all child classes without modification
Can be used directly
4. Child Classes:
Dog and Cat inherit from Animal
Both must implement speak() method
Both get introduce() for free
Example 2: Abstract Class with Multiple Abstract Methods
from abc import ABC, abstractmethod
# Abstract class for geometric shapes
class Shape(ABC):
def __init__(self, color):
[Link] = color
# Abstract methods - must be implemented
@abstractmethod
def area(self):
"""Calculate and return the area"""
pass
@abstractmethod
def perimeter(self):
"""Calculate and return the perimeter"""
pass
# Concrete method - shared functionality
def display_color(self):
print(f"Color: {[Link]}")
def description(self):
print(f"This is a {[Link]} {self.__class__.__name__}")
print(f"Area: {[Link]():.2f}")
print(f"Perimeter: {[Link]():.2f}")
# Concrete class 1: Rectangle
class Rectangle(Shape):
def __init__(self, color, length, width):
super().__init__(color)
[Link] = length
[Link] = width
def area(self):
return [Link] * [Link]
def perimeter(self):
return 2 * ([Link] + [Link])
# Concrete class 2: Circle
class Circle(Shape):
def __init__(self, color, radius):
super().__init__(color)
[Link] = radius
def area(self):
return 3.14159 * ([Link] ** 2)
def perimeter(self):
return 2 * 3.14159 * [Link]
# Create objects
rectangle = Rectangle("Blue", 5, 3)
circle = Circle("Red", 4)
print("=== Rectangle ===")
[Link]()
print("\n=== Circle ===")
[Link]()
# Demonstrate polymorphism
print("\n=== All Shapes ===")
shapes = [rectangle, circle]
for shape in shapes:
print(f"\n{shape.__class__.__name__}:")
shape.display_color()
print(f"Area: {[Link]():.2f}")
Output:
=== Rectangle ===
This is a Blue Rectangle
Area: 15.00
Perimeter: 16.00
=== Circle ===
This is a Red Circle
Area: 50.27
Perimeter: 25.13
=== All Shapes ===
Rectangle:
Color: Blue
Area: 15.00
Circle:
Color: Red
Area: 50.27
Detailed Explanation:
1. Multiple Abstract Methods:
area() and perimeter() must both be implemented
Child classes cannot skip implementing any abstract method
2. Shared Functionality:
display_color() and description() are concrete methods
All child classes inherit and can use them
Reduces code duplication
3. Polymorphism:
All shapes can be stored in a single list
Can call area() on any shape
Each shape calculates differently
6. Abstract Methods and Concrete Methods
Abstract Methods
Definition: Methods declared in an abstract class but have no implementation. Child classes must provide the
implementation.
Characteristics:
1. Decorated with @abstractmethod
2. Can have just pass or ... or a docstring
3. Cannot be called directly
4. Must be overridden in child classes
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount):
"""Process payment of given amount"""
pass
@abstractmethod
def refund(self, transaction_id):
"""Refund a transaction"""
...
@abstractmethod
def get_transaction_status(self, transaction_id):
"""
Get status of a transaction.
Returns: 'success', 'pending', or 'failed'
"""
# Abstract methods can have docstrings
pass
Concrete Methods
Definition: Regular methods with complete implementation in the abstract class. Child classes inherit them
as-is.
Characteristics:
1. No @abstractmethod decorator
2. Have full implementation
3. Can be used directly by child classes
4. Can be overridden if needed
from abc import ABC, abstractmethod
class DatabaseConnection(ABC):
def __init__(self, host, port):
[Link] = host
[Link] = port
self.is_connected = False
# Abstract method
@abstractmethod
def connect(self):
pass
# Concrete method
def get_connection_string(self):
return f"{[Link]}:{[Link]}"
# Concrete method
def log_activity(self, message):
print(f"[{self.__class__.__name__}] {message}")
Combining Both Types
from abc import ABC, abstractmethod
class FileHandler(ABC):
def __init__(self, filename):
[Link] = filename
self.is_open = False
# Abstract methods - different for each file type
@abstractmethod
def read(self):
pass
@abstractmethod
def write(self, data):
pass
# Concrete methods - same for all file types
def open_file(self):
self.is_open = True
print(f"Opening {[Link]}")
def close_file(self):
self.is_open = False
print(f"Closing {[Link]}")
def get_filename(self):
return [Link]
# Child class 1: Text files
class TextFileHandler(FileHandler):
def read(self):
if self.is_open:
return f"Reading text from {[Link]}"
return "File not open"
def write(self, data):
if self.is_open:
print(f"Writing text to {[Link]}: {data}")
# Child class 2: Binary files
class BinaryFileHandler(FileHandler):
def read(self):
if self.is_open:
return f"Reading binary data from {[Link]}"
return "File not open"
def write(self, data):
if self.is_open:
print(f"Writing binary data to {[Link]}")
# Using the classes
print("=== Text File ===")
text_file = TextFileHandler("[Link]")
text_file.open_file() # Concrete method
print(text_file.read()) # Abstract method implemented
text_file.write("Hello, World!") # Abstract method implemented
text_file.close_file() # Concrete method
print("\n=== Binary File ===")
binary_file = BinaryFileHandler("[Link]")
binary_file.open_file() # Concrete method
print(binary_file.read()) # Abstract method implemented
binary_file.write(b"binary_data") # Abstract method implemented
binary_file.close_file() # Concrete method
Output:
=== Text File ===
Opening [Link]
Reading text from [Link]
Writing text to [Link]: Hello, World!
Closing [Link]
=== Binary File ===
Opening [Link]
Reading binary data from [Link]
Writing binary data to [Link]
Closing [Link]
Explanation:
Abstract methods ( read() , write() ) are implemented differently in each child class
Concrete methods ( open_file() , close_file() , get_filename() ) work the same for all child
classes
This reduces code duplication while maintaining flexibility
7. Interfaces in Python
What is an Interface?
An Interface is a contract that defines what methods a class must implement, without providing any
implementation. It’s like a blueprint that specifies “what” must be done, not “how” to do it.
Key Characteristics:
1. Contains only method signatures (no implementation)
2. Cannot be instantiated
3. Classes that implement the interface must provide all methods
4. Used to achieve 100% abstraction
Interfaces in Other Languages vs Python
In Java/C#:
Have a dedicated interface keyword
Interfaces cannot have any implementation
In Python:
No separate interface keyword
Interfaces are created using abstract classes with only abstract methods
Sometimes called “Pure Abstract Classes”
Creating Interfaces in Python
from abc import ABC, abstractmethod
# This is an interface (pure abstract class)
class PaymentInterface(ABC):
@abstractmethod
def make_payment(self, amount):
pass
@abstractmethod
def verify_payment(self, transaction_id):
pass
@abstractmethod
def cancel_payment(self, transaction_id):
pass
# No concrete methods - only abstract methods
# This makes it a pure interface
Interface vs Abstract Class
Feature Interface Abstract Class
Methods Only abstract methods Abstract + Concrete methods
Implementation No implementation Can have some implementation
Purpose Define contract Provide base functionality
Abstraction Level 100% abstraction Partial abstraction
Use Case “What” must be done “What” + some “How”
8. Implementing Interfaces
Example 1: Simple Interface Implementation
from abc import ABC, abstractmethod
# Interface definition
class Drawable(ABC):
@abstractmethod
def draw(self):
"""Draw the object"""
pass
@abstractmethod
def resize(self, scale):
"""Resize the object"""
pass
# Class 1 implementing the interface
class Circle(Drawable):
def __init__(self, radius):
[Link] = radius
def draw(self):
print(f"Drawing a circle with radius {[Link]}")
def resize(self, scale):
[Link] *= scale
print(f"Circle resized. New radius: {[Link]}")
# Class 2 implementing the interface
class Rectangle(Drawable):
def __init__(self, width, height):
[Link] = width
[Link] = height
def draw(self):
print(f"Drawing a rectangle {[Link]}x{[Link]}")
def resize(self, scale):
[Link] *= scale
[Link] *= scale
print(f"Rectangle resized. New dimensions: {[Link]}x{[Link]}")
# Class 3 implementing the interface
class Triangle(Drawable):
def __init__(self, base, height):
[Link] = base
[Link] = height
def draw(self):
print(f"Drawing a triangle with base {[Link]} and height {[Link]}")
def resize(self, scale):
[Link] *= scale
[Link] *= scale
print(f"Triangle resized. New dimensions: base={[Link]}, height={[Link]
t}")
# Using the interface - Polymorphism
def render_shape(shape: Drawable):
"""Function accepts any object that implements Drawable interface"""
[Link]()
[Link](1.5)
# Create objects
circle = Circle(5)
rectangle = Rectangle(10, 20)
triangle = Triangle(8, 6)
# All can be treated uniformly because they implement the same interface
shapes = [circle, rectangle, triangle]
print("=== Rendering All Shapes ===")
for shape in shapes:
render_shape(shape)
print()
Output:
=== Rendering All Shapes ===
Drawing a circle with radius 5
Circle resized. New radius: 7.5
Drawing a rectangle 10x20
Rectangle resized. New dimensions: 15.0x30.0
Drawing a triangle with base 8 and height 6
Triangle resized. New dimensions: base=12.0, height=9.0
Detailed Explanation:
1. Interface Drawable :
Defines two methods: draw() and resize()
No implementation, only signatures
Acts as a contract
2. Three Implementations:
Circle, Rectangle, and Triangle all implement Drawable
Each provides its own implementation
All satisfy the interface contract
3. Polymorphism:
render_shape() function accepts any Drawable object
Works with Circle, Rectangle, or Triangle
Doesn’t need to know the specific type
Example 2: Multiple Interfaces
from abc import ABC, abstractmethod
# Interface 1: Playable
class Playable(ABC):
@abstractmethod
def play(self):
pass
@abstractmethod
def pause(self):
pass
@abstractmethod
def stop(self):
pass
# Interface 2: Downloadable
class Downloadable(ABC):
@abstractmethod
def download(self):
pass
@abstractmethod
def get_file_size(self):
pass
# Class implementing both interfaces
class VideoFile(Playable, Downloadable):
def __init__(self, title, duration, file_size_mb):
[Link] = title
[Link] = duration
self.file_size_mb = file_size_mb
self.is_playing = False
# Implementing Playable interface
def play(self):
self.is_playing = True
print(f"Playing video: {[Link]}")
def pause(self):
print(f"Paused: {[Link]}")
def stop(self):
self.is_playing = False
print(f"Stopped: {[Link]}")
# Implementing Downloadable interface
def download(self):
print(f"Downloading {[Link]} ({self.file_size_mb} MB)...")
print("Download complete!")
def get_file_size(self):
return self.file_size_mb
# Class implementing only Playable
class AudioFile(Playable):
def __init__(self, title, artist):
[Link] = title
[Link] = artist
def play(self):
print(f"Playing song: {[Link]} by {[Link]}")
def pause(self):
print(f"Paused: {[Link]}")
def stop(self):
print(f"Stopped: {[Link]}")
# Using the interfaces
video = VideoFile("Python Tutorial", "15:30", 250)
audio = AudioFile("Imagine", "John Lennon")
print("=== Video File (Playable + Downloadable) ===")
[Link]()
[Link]()
[Link]()
print(f"File size: {video.get_file_size()} MB")
[Link]()
print("\n=== Audio File (Playable only) ===")
[Link]()
[Link]()
[Link]()
Output:
=== Video File (Playable + Downloadable) ===
Playing video: Python Tutorial
Paused: Python Tutorial
Stopped: Python Tutorial
File size: 250 MB
Downloading Python Tutorial (250 MB)...
Download complete!
=== Audio File (Playable only) ===
Playing song: Imagine by John Lennon
Paused: Imagine
Stopped: Imagine
Explanation:
VideoFile implements both Playable and Downloadable interfaces
AudioFile implements only Playable interface
Each class must implement all methods from its interfaces
This is multiple interface implementation (similar to multiple inheritance)
Summary
Key Concepts to Remember
1. Abstraction
Hides complex implementation details
Shows only essential features
Achieved through abstract classes and interfaces
2. Abstract Classes
Cannot be instantiated
May contain abstract and concrete methods
Serve as blueprints for child classes
Created using abc module
3. Abstract Methods
Declared with @abstractmethod decorator
Have no implementation in abstract class
Must be implemented by all child classes
Define the contract
4. Interfaces in Python
Pure abstract classes (only abstract methods)
Define what must be done, not how
Achieved using ABC with only abstract methods
Enable polymorphism and flexibility
5. The abc Module
ABC class - base for abstract classes
abstractmethod - decorator for abstract methods
Enforces implementation in child classes
Prevents instantiation of abstract classes
Benefits of Abstraction
1. Simplicity - Complex details hidden
2. Security - Implementation details protected
3. Flexibility - Easy to add new implementations
4. Maintainability - Changes don’t break user code
5. Clear Contracts - Everyone knows what to implement
6. Polymorphism - Work with multiple types uniformly
When to Use
Abstract Classes: When you want to provide some shared implementation along with abstract
methods
Interfaces: When you want to define a pure contract with no implementation
Both: When designing frameworks, plugins, or extensible systems
Best Practices
1. Keep interfaces small and focused
2. Document abstract methods clearly
3. Use type hints for better code clarity
4. Prefer composition over inheritance when possible
5. Follow SOLID principles (especially Interface Segregation)
6. Name abstract classes/interfaces clearly (e.g., Drawable , Payable )
By understanding and properly using abstraction and interfaces, you can write more maintainable, flexible, and
professional Python code that’s easy to extend and modify.