An Abstract Base Class (ABC) in Python is a class that serves as a blueprint for other classes. It defines a common interface for its subclasses but cannot be instantiated directly. Instead, it enforces that subclasses implement specific methods defined in the abstract class. This ensures consistency and allows polymorphism in your code.

Why Use Abstract Base Classes?

1. Enforcing Contracts:
o Ensures that all subclasses implement certain methods, maintaining a consistent interface.

2. Improved Code Clarity:
o Clearly defines expected behavior, making the code easier to understand and maintain.

3. Facilitating Polymorphism:
o Subclasses can be used interchangeably if they adhere to the abstract base class interface.

4. Providing Default Implementations:
o Abstract base classes can define concrete methods that subclasses inherit, reducing redundant code.

Real-Life Analogy

Imagine a Payment System:
• All payment methods (like CreditCard, PayPal, and BankTransfer) share common behaviors, such as pay and refund.
• An ABC called PaymentMethod could define these behaviors as abstract methods. Any subclass of PaymentMethod must implement the pay and refund methods, ensuring a consistent interface across all payment types.

Creating and Using Abstract Base Classes

Python provides the abc module to create abstract base classes.
Basic Syntax

from abc import ABC, abstractmethod
    
class AbstractClass(ABC):
    @abstractmethod
    def some_method(self):
        pass

1. Import the ABC and abstractmethod decorators from the abc module.

Example: Payment System

    from abc import ABC, abstractmethod
    
    # Define Abstract Base Class
    class PaymentMethod(ABC):
        @abstractmethod
        def pay(self, amount):
            """Process the payment"""
            pass
    
        @abstractmethod
        def refund(self, amount):
            """Process the refund"""
            pass
    
    # Subclass: Credit Card
    class CreditCard(PaymentMethod):
        def pay(self, amount):
            return f"Paid ${amount} using Credit Card."
    
        def refund(self, amount):
            return f"Refunded ${amount} to Credit Card."
    
    # Subclass: PayPal
    class PayPal(PaymentMethod):
        def pay(self, amount):
            return f"Paid ${amount} using PayPal."
    
        def refund(self, amount):
            return f"Refunded ${amount} to PayPal."
    
    # Usage
    def process_payment(payment_method, amount):
        print(payment_method.pay(amount))
        print(payment_method.refund(amount))
    
    credit_card = CreditCard()
    paypal = PayPal()
    
    process_payment(credit_card, 100)  # Output: Paid $100 using Credit Card.
    process_payment(paypal, 200)      # Output: Paid $200 using PayPal.

Key Concepts of Abstract Base Classes

1. Cannot Instantiate Abstract Classes: o You cannot create objects of an ABC directly.

payment = PaymentMethod()  # Raises TypeError

2. Abstract Methods Must Be Implemented: o Subclasses must implement all abstract methods of the ABC; otherwise, they cannot be instantiated.

3. Optional Concrete Methods: o Abstract base classes can also define concrete methods that subclasses inherit.

Real-World Example: Shapes

Consider an application that calculates areas for different shapes like circles and rectangles.

    from abc import ABC, abstractmethod
    import math
    
    class Shape(ABC):
        @abstractmethod
        def area(self):
            pass
    
        @abstractmethod
        def perimeter(self):
            pass
    
    class Circle(Shape):
        def __init__(self, radius):
            self.radius = radius
    
        def area(self):
            return math.pi * self.radius**2
    
        def perimeter(self):
            return 2 * math.pi * self.radius
    
    class Rectangle(Shape):
        def __init__(self, width, height):
            self.width = width
            self.height = height
    
        def area(self):
            return self.width * self.height
    
        def perimeter(self):
            return 2 * (self.width + self.height)
    
    # Usage
    shapes = [Circle(5), Rectangle(4, 6)]
    
    for shape in shapes:
        print(f"Area: {shape.area()}, Perimeter: {shape.perimeter()}")
    

Abstract Base Classes with Concrete Methods

You can define concrete methods in ABCs to provide default implementations.

from abc import ABC, abstractmethod
    
    class Employee(ABC):
        def __init__(self, name):
            self.name = name
    
        @abstractmethod
        def get_salary(self):
            pass
    
        def display(self):
            return f"Employee Name: {self.name}"
    
    class FullTimeEmployee(Employee):
        def get_salary(self):
            return "Salary is $5000/month"
    
    class PartTimeEmployee(Employee):
        def get_salary(self):
            return "Salary is $20/hour"
    
    # Usage
    fte = FullTimeEmployee("Alice")
    pte = PartTimeEmployee("Bob")
    
    print(fte.display())       # Output: Employee Name: Alice
    print(fte.get_salary())    # Output: Salary is $5000/month
    print(pte.display())       # Output: Employee Name: Bob
    print(pte.get_salary())    # Output: Salary is $20/hour

Using ABC with Built-In Collections

Abstract Base Classes in Python’s collections.abc module define interfaces for container types like lists, sets, and dictionaries.

from collections.abc import MutableSequence
    
    class CustomList(MutableSequence):
        def __init__(self):
            self._data = []
    
        def __getitem__(self, index):
            return self._data[index]
    
        def __setitem__(self, index, value):
            self._data[index] = value
    
        def __delitem__(self, index):
            del self._data[index]
    
        def __len__(self):
            return len(self._data)
    
        def insert(self, index, value):
            self._data.insert(index, value)
    
    # Usage
    cl = CustomList()
    cl.insert(0, "a")
    cl.insert(1, "b")
    print(cl)  # Output: ['a', 'b']

Key Benefits of Abstract Base Classes

1. Consistency: o Ensures subclasses follow a consistent interface.

2. Readability: o Clearly defines what a class is expected to implement.

3. Polymorphism: o Enables using objects interchangeably, as long as they implement the required methods.

When to Use Abstract Base Classes

1. Defining Interfaces: o When you want to enforce that all subclasses implement specific methods.

2. Extending Frameworks: o For example, building plugins or APIs where subclasses must adhere to a contract.

3. Shared Behavior with Default Implementations: o Provide shared behavior through concrete methods in the ABC while allowing customization.

Best Practices

1. Avoid Overuse: o Use ABCs only when you need to enforce strict method implementation.

2. Keep It Simple: o Avoid creating overly complex hierarchies with multiple ABCs.

3. Document the Contract: o Clearly explain in the docstring what methods must be implemented by subclasses.

Summary

Abstract Base Classes (ABC):
o Provide a blueprint for other classes.
o Enforce that subclasses implement certain methods.
o Cannot be instantiated directly.

• Key Features:
o Abstract methods must be implemented.
o Optional concrete methods can provide default behavior.

• Use Cases:
o Enforcing contracts, polymorphism, defining frameworks, and creating consistent interfaces.