In Python object-orianted programming, inheritance and abstract classes are fundamental concepts that enable code reuse and interface definition. Inheritance allows a class to acquire attributes and methods from another class, while abstract classes define a contract that derived classes must implement.
Inheritance Basics
Inheritance creates a parent-child relationship between classes. A subclass inherits all attributes and methods from its parent class, allowing you to extend functionality without modifying existing code.
class Shape:
def __init__(self, color):
self.color = color
def area(self):
raise NotImplementedError("Derived class must implement area method")
class Rectangle(Shape):
def __init__(self, color, width, height):
super().__init__(color)
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, color, radius):
super().__init__(color)
self.radius = radius
def area(self):
import math
return math.pi * self.radius ** 2
rect = Rectangle("blue", 5, 3)
circle = Circle("red", 2)
print(f"Rectangle area: {rect.area()}")
print(f"Circle area: {circle.area():.2f}")
The Rectangle and Circle classes inherit from Shape and override the area method to provide specific implementations.
Abstract Classes with ABC
Abstract classes cannot be instantiated directly. They serve as blueprints that define a set of methods all derived classes must implement. Python's abc module provides the ABC class and abstractmethod decorator for this purpose.
from abc import ABC, abstractmethod
import math
class Polygon(ABC):
def __init__(self, side_count):
self.sides = side_count
@abstractmethod
def calculate_perimeter(self):
pass
class Triangle(Polygon):
def __init__(self, a, b, c):
super().__init__(3)
self.edges = (a, b, c)
def calculate_perimeter(self):
return sum(self.edges)
class Square(Polygon):
def __init__(self, side):
super().__init__(4)
self.side = side
def calculate_perimeter(self):
return 4 * self.side
triangle = Triangle(3, 4, 5)
square = Square(6)
print(f"Triangle perimeter: {triangle.calculate_perimeter()}")
print(f"Square perimeter: {square.calculate_perimeter()}")
The abstract base class Polygon defines the interface with calculate_perimeter, which each concrete subclass must implement.
Practical Application
Abstract classes are particularly useful in larger applications where you need to enforce consistent interfaces across multiple implementations.
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
def __init__(self, account_id):
self.account_id = account_id
self.balance = 0.0
@abstractmethod
def process_payment(self, amount):
pass
@abstractmethod
def refund(self, amount):
pass
class CreditCardProcessor(PaymentProcessor):
def process_payment(self, amount):
self.balance += amount
return f"Credit card charge of ${amount:.2f} processed"
def refund(self, amount):
self.balance -= amount
return f"Credit card refund of ${amount:.2f} processed"
class PayPalProcessor(PaymentProcessor):
def process_payment(self, amount):
self.balance += amount
return f"PayPal payment of ${amount:.2f} completed"
def refund(self, amount):
self.balance -= amount
return f"PayPal refund of ${amount:.2f} completed"
credit_processor = CreditCardProcessor("CC-12345")
paypal_processor = PayPalProcessor("PP-67890")
print(credit_processor.process_payment(150.00))
print(paypal_processor.process_payment(75.50))
print(credit_processor.refund(25.00))
This pattern allows you to swap payment processors without changing the code that uses them, following the strategy design pattern.