top

Search

Python Tutorial

.

UpGrad

Python Tutorial

Abstract Class in Python

Introduction

Imagine you're constructing a complex software system where different classes need to follow a set of rules, ensuring they work harmoniously together. It is where Abstract Base Classes (ABCs) assist. ABC Python is like the architects of your code, defining the blueprint every subclass must adhere to.

In this article, we will look at ABCs, how they vary from regular classes, and understand why they are crucial in object-oriented programming.

Overview

An Abstract Base Class (ABC) is a concept in object-oriented programming that serves as a blueprint or template to create classes. It defines a set of methods and attributes implemented by any concrete subclass that inherits from it. Abstract Base Classes are used to enforce a specific interface or contract, ensuring all subclasses adhere to a consistent structure and behavior.

Why use Abstract Base Classes?

Let us understand what is the purpose of an Abstract class in Python. Abstract Python base class serves several important purposes:

Enforce a Contract: ABC Python defines a contract that subclasses must adhere to. This contract specifies which methods and attributes must be implemented by any concrete subclass and gives consistency and correctness in the codebase.

Provide a Common Interface: ABCs define a common set of methods used uniformly across different subclasses. It allows code to be more generic and flexible, as it can work with any class that conforms to the ABC.

Documentation and Guidance: ABCs serve as documentation for the expected behavior of subclasses. Developers can see which methods must be implemented and make it easier to understand and extend the codebase.

Polymorphism and Type Safety: They enable polymorphism, simplifying code reusability and type checking by ensuring shared methods and attributes among objects.

Error Prevention and Validation: ABCs detect errors during design by verifying concrete subclasses implement all required methods and reduce runtime issues.

Let's illustrate this with an example in ABC Python:

code
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14 * self.radius * self.radius

class Rectangle(Shape):
    def __init__(self, length, width):
        self.length = length
        self.width = width
    
    def area(self):
        return self.length * self.width

Here, Shape is an abstract base class with an abstract method in the Python example area(). Circle and Rectangle are concrete subclasses of Shape, and they implement the area() method as required.

How do Abstract Base Classes Work? 

Abstract Base Classes define a class hierarchy in which some methods are marked as abstract using the @abstractmethod decorator. Subclasses must implement these abstract methods to be considered valid.

In Python, you need to import the ABC class and the abstractmethod decorator from the abc module.

Here's a breakdown of how they work:

  • Define an abstract Python base class by subclassing ABC.

  • Use the @abstractmethod decorator to declare abstract methods within the abstract base class.

  • Concrete subclasses inherit from the abstract base class and implement the abstract methods.

  • Instances of concrete subclasses can be created and used just like regular objects.

Implementation Through Subclassing 

To implement an abstract Python base class through subclassing, follow these steps:

  • Create an abstract base class by subclassing ABC.

  • Define one or more abstract methods within the abstract base class using the @abstractmethod decorator.

  • Create concrete subclasses that inherit from the abstract base class.

  • Implement the abstract methods in each concrete subclass.

Concrete Methods in Abstract Base Classes

Abstract base classes can contain abstract methods and concrete (non-abstract) methods. Concrete methods provide a default implementation that subclasses can override but is not mandatory.

Here's an abstract method in Python example:

code
from abc import ABC, abstractmethod

class Vehicle(ABC):
    @abstractmethod
    def start_engine(self):
        pass

    def stop_engine(self):
        print("Engine stopped")

class Car(Vehicle):
    def start_engine(self):
        print("Car engine started")

# Create an instance of Car
car = Car()
car.start_engine()  # Output: Car engine started
car.stop_engine()   # Output: Engine stopped

In this example, Vehicle is an abstract Python base class with an abstract method start_engine() and a concrete method stop_engine(). The Car subclass implements the start_engine() method but inherits the stop_engine() method.

Abstract Properties 

Abstract properties are attributes defined in an abstract base class that must be implemented as properties (getter and/or setter methods) by subclasses. You can use the @property decorator to define abstract properties.

Example of Python abstract class property:

code
from abc import ABC, abstractmethod

class Shape(ABC):
    @property
    @abstractmethod
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self._radius = radius
    
    @property
    def area(self):
        return 3.14 * self._radius * self._radius

class Rectangle(Shape):
    def __init__(self, length, width):
        self._length = length
        self._width = width
    
    @property
    def area(self):
        return self._length * self._width

Shape is an abstract base class with a Python abstract class property area in this example. Circle and Rectangle are concrete subclasses of Shape that implement the area property.

Abstract Class in Python Instantiation

Abstract base classes cannot be instantiated directly. You can only create instances of concrete subclasses. Attempting to create an instance of an abstract base class will raise a TypeError.

Example:

code
from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self):
        pass

# Attempt to create an instance of the abstract base class
animal = Animal()  # This will raise a TypeError

In this example, trying to create an instance of the abstract base class Animal results in an error. You must create instances of concrete subclasses like Dog or Cat instead.

Why is Abstraction in Python Important?

Abstraction in Python is important in programming for several reasons:

1. Encapsulation: Abstraction in Python allows you to hide the internal details of an object and expose only what is necessary. This promotes encapsulation, a fundamental principle of object-oriented programming.

Example:

In a banking application, you can abstract a BankAccount class to encapsulate the details of an account while providing methods like deposit and withdrawal for interaction.

2. Code Reusability: Abstract base classes provide a blueprint for creating subclasses with shared behavior. This promotes code reusability and reduces duplication.

Example:

In a game development framework, an abstract GameObject class can define methods like update and render that all game objects must implement.

3. Maintenance and Extensibility: Abstraction in Python makes maintaining and extending your code easier. When you need to make changes, you can focus on the abstract interface, knowing that all subclasses will follow the same contract.

Example:

Adding new shapes to a drawing application becomes straightforward when you have an abstract Shape class that defines methods like area and draw.

4. Design Patterns: Abstraction is a fundamental concept in many design patterns, such as the Factory Method, Strategy, and Observer patterns. These patterns rely on abstract base classes to achieve flexibility and modularity.

Example:

The Strategy pattern uses abstract classes to define interchangeable algorithms that can be used in different contexts.

Working of the Abstract Classes

Abstract classes work by defining a contract that subclasses must adhere to. They provide a blueprint for creating related classes with a standard interface and shared behavior. Here's how they work:

Step 1: Defining an Abstract Class

You typically use the ABC (Abstract Base Class) module and the @abstractmethod decorator to create an abstract class in Python. An abstract class is defined by subclassing ABC Python and declaring one or more abstract methods using the @abstractmethod decorator.

code
from abc import ABC, abstractmethod

class AbstractClass(ABC):
    @abstractmethod
    def abstract_method(self):
        pass

    def concrete_method(self):
        print("This is a concrete method.")

In this example, AbstractClass is an abstract class in Python with an abstract method abstract_method() and a concrete method concrete_method().

Step 2: Creating Concrete Subclasses

Concrete subclasses are classes that inherit from the abstract class in Python and provide implementations for the abstract method in Python defined in the abstract class.

code
class ConcreteClass(AbstractClass):
    def abstract_method(self):
        print("Implemented abstract_method in ConcreteClass.")

    def additional_method(self):
        print("This is an additional method.")

Here, ConcreteClass is a concrete subclass of AbstractClass, and it provides an implementation for the abstract_method().

Step 3: Instantiation

You cannot create an instance of an abstract class in Python directly. Attempting to do so will result in a TypeError. You can only create instances of concrete subclasses.

code
# Attempting to create an instance of the abstract class
# This will raise a TypeError
abstract_instance = AbstractClass()

# Creating an instance of the concrete subclass
concrete_instance = ConcreteClass()

In this example, abstract_instance = AbstractClass() will raise a TypeError, but concrete_instance = ConcreteClass() is valid.

Step 4: Polymorphism

Polymorphism allows you to work with objects of different subclasses through a common interface. Since the abstract class and its concrete subclasses adhere to the same interface, you can use polymorphism to interact with them uniformly.

code
def use_abstract_class(instance):
    instance.abstract_method()
    instance.concrete_method()

# Using the abstract class and its concrete subclass
use_abstract_class(concrete_instance)

In this example, the use_abstract_class function can take either an instance of the abstract class or its concrete subclass, and it calls abstract_method() and concrete_method().

Step 5: Enforcing a Contract

Abstract classes enforce a contract by ensuring that all concrete subclasses provide implementations for the abstract methods. If a concrete subclass doesn't implement all the abstract methods, it will be considered abstract and cannot be instantiated.

Code
class IncompleteConcreteClass(AbstractClass):
    def concrete_method(self):
        print("Implemented concrete_method in IncompleteConcreteClass.")

# Attempting to create an instance of an incomplete concrete class
incomplete_instance = IncompleteConcreteClass()

In this example, IncompleteConcreteClass does not implement abstract_method(), so to create an instance of it will raise a TypeError.

In this example, we'll create an abstract class in Python called Shape with abstract methods for calculating area and perimeter. Then we'll create concrete subclasses to implement these methods for specific shapes such as circles and rectangles.

code
from abc import ABC, abstractmethod
import math

# Step 1: Define an abstract class 'Shape'
class Shape(ABC):
    def __init__(self, name):
        self.name = name

    @abstractmethod
    def calculate_area(self):
        pass

    @abstractmethod
    def calculate_perimeter(self):
        pass

    def display_info(self):
        print(f"Shape: {self.name}")
        print(f"Area: {self.calculate_area()}")
        print(f"Perimeter: {self.calculate_perimeter()}")

# Step 2: Create concrete subclasses

# Subclass 1: Circle
class Circle(Shape):
    def __init__(self, name, radius):
        super().__init__(name)
        self.radius = radius

    def calculate_area(self):
        return math.pi * self.radius ** 2

    def calculate_perimeter(self):
        return 2 * math.pi * self.radius

# Subclass 2: Rectangle
class Rectangle(Shape):
    def __init__(self, name, length, width):
        super().__init__(name)
        self.length = length
        self.width = width

    def calculate_area(self):
        return self.length * self.width

    def calculate_perimeter(self):
        return 2 * (self.length self.width)

# Step 3: Create instances of concrete subclasses
circle = Circle("Circle 1", 5)
rectangle = Rectangle("Rectangle 1", 4, 6)

# Step 4: Use the abstract class methods
circle.display_info()
print("--------------------------")
rectangle.display_info()

Conclusion

Abstract Base Classes design object-oriented programs that emphasize encapsulation, reusability, and maintainability. By defining abstract methods, properties, and classes, you can create a clear structure for your code and ensure subclasses have a common interface.

This guide has provided an all-around overview of Abstract Classes in Python and their importance in programming using real-world examples and practical explanations. Using abstraction, programmers can make robust and flexible codebases and make software development projects more successful.

FAQs

1. Can you have concrete methods in an abstract base class? 

Yes, you can have concrete (non-abstract) methods in an abstract base class. These methods provide default behavior overridden by subclasses but are not mandatory.

2. Is it possible to inherit from multiple abstract base classes in Python?

Yes, Python supports multiple inheritance, which means you can inherit from multiple abstract base classes. However, be careful when dealing with potential conflicts in method names and behaviors.

3. Can I define abstract properties in an ABC?

Yes, you can define abstract properties in an ABC using the @property decorator. Subclasses must provide the getter and/or setter methods for these properties.

4. Are abstract base classes specific to Python? 

No, abstract base classes are not specific to Python. They are a concept found in many object-oriented programming languages, although the implementation details may vary.

Leave a Reply

Your email address will not be published. Required fields are marked *