w3resource

Python Abstraction with examples: Abstract Classes and Interfaces

Introduction to Python Abstraction

Abstraction is one of the fundamental principles of object-oriented programming (OOP). It allows you to define the structure of a class without implementing the full functionality. In Python, abstraction is typically achieved using abstract classes and interfaces.

Let's explore abstraction in Python with examples, explanations, and descriptions.

Example 1: Abstract Classes Using abc Module

An abstract class in "Python" is a class that cannot be instantiated and often contains one or more abstract methods. Abstract methods are methods that are declared but contain no implementation. To create an abstract class in Python, you use the "abc" (Abstract Base Class) module.

Code:

from abc import ABC, abstractmethod  # Importing ABC and abstractmethod from the abc module
# Abstract base class
class Shape(ABC):  # Inheriting from ABC to make this an abstract class
    @abstractmethod
    def area(self):
        pass  # Abstract method with no implementation

    @abstractmethod
    def perimeter(self):
        pass  # Abstract method with no implementation

# Derived class 1: Rectangle
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height  # Implementing the abstract method

    def perimeter(self):
        return 2 * (self.width + self.height)  # Implementing the abstract method

# Derived class 2: Circle
class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * (self.radius ** 2)  # Implementing the abstract method

    def perimeter(self):
        return 2 * 3.14 * self.radius  # Implementing the abstract method

# Creating instances of Rectangle and Circle
rectangle = Rectangle(12, 14)
circle = Circle(3)

# Calling methods
print(f"Rectangle Area: {rectangle.area()}")        # Output: Rectangle Area: 168
print(f"Rectangle Perimeter: {rectangle.perimeter()}")  # Output: Rectangle Perimeter: 52
print(f"\nCircle Area: {circle.area()}")              # Output: Circle Area: 28.26
print(f"Circle Perimeter: {circle.perimeter()}")    # Output: Circle Perimeter: 18.84

Explanation:

Abstract Base Class ('Shape'):

  • The Shape class is an abstract class, indicated by inheriting from ABC.
  • It defines two abstract methods, 'area' and 'perimeter', using the '@abstractmethod' decorator. These methods are defined but not implemented, meaning any subclass must provide an implementation for these methods.

Protected Methods:

  • The _speak method in the Animal class is protected. It is meant to be used within the class or subclasses but not from outside.

Derived Classes ('Rectangle' and 'Circle'):

  • The 'Rectangle' and 'Circle' classes inherit from Shape and provide specific implementations for the area and perimeter methods.
  • Each subclass calculates the area and perimeter according to its geometric shape.

Instantiation and Method Calls:

  • Instances of 'Rectangle' and 'Circle' are created, and their area and perimeter methods are called.
  • The output shows the correct area and perimeter based on the provided dimensions, demonstrating how abstraction allows different shapes to share a common interface ('Shape') while implementing specific behaviors.

Example 2: Using an Interface-Like Structure

In Python, interfaces aren't a built-in feature like in some other languages (e.g., Java). However, you can create an interface-like structure using abstract base classes.

Code:

from abc import ABC, abstractmethod

# Interface-like abstract base class
class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass  # Abstract method

    @abstractmethod
    def move(self):
        pass  # Abstract method

# Implementing the interface in the Dog class
class Dog(Animal):
    def sound(self):
        return "Bark!"  # Implementing the sound method

    def move(self):
        return "Runs"  # Implementing the move method

# Implementing the interface in the Bird class
class Bird(Animal):
    def sound(self):
        return "Chirp!"  # Implementing the sound method

    def move(self):
        return "Flies"  # Implementing the move method

# Creating instances of Dog and Bird
dog = Dog()
bird = Bird()

# Calling methods
print(f"Dog Sound: {dog.sound()}")  # Output: Dog Sound: Bark!
print(f"Dog Movement: {dog.move()}")  # Output: Dog Movement: Runs
print(f"Bird Sound: {bird.sound()}")  # Output: Bird Sound: Chirp!
print(f"Bird Movement: {bird.move()}")  # Output: Bird Movement: Flies

Explanation:

Interface-Like Abstract Base Class ('Animal'):

  • The 'Animal' class acts as an interface by defining the methods 'sound' and 'move' as abstract methods. Any class inheriting from 'Animal' must implement these methods.

Implementing the Interface in 'Dog' and 'Bird' Classes:

  • The 'Dog' and 'Bird' classes inherit from Animal and provide specific implementations for the 'sound' and 'move' methods.
  • Each class tailors these methods to represent the behavior of the specific animal.
  • Instantiation and Method Calls:
    • Instances of 'Dog' and 'Bird' are created, and their 'sound' and 'move' methods are called.
    • The output reflects the behavior specific to each animal, showcasing how abstract classes can be used as interfaces to enforce a consistent API while allowing for different implementations.

    Example 3: Preventing Instantiation of Abstract Classes

    Abstract classes are meant to define a common interface and should not be instantiated directly. Attempting to instantiate an abstract class will raise a 'TypeError'.

    Code:

    from abc import ABC, abstractmethod
    
    # Abstract base class
    class Appliance(ABC):
        @abstractmethod
        def turn_on(self):
            pass  # Abstract method
    
        @abstractmethod
        def turn_off(self):
            pass  # Abstract method
    
    # Derived class: WashingMachine
    class WashingMachine(Appliance):
        def turn_on(self):
            return "Washing Machine is now ON."
    
        def turn_off(self):
            return "Washing Machine is now OFF."
    
    # Trying to create an instance of Appliance (abstract class)
    # appliance = Appliance()  # Uncommenting this line will raise a TypeError
    
    # Creating an instance of WashingMachine
    washing_machine = WashingMachine()
    
    # Calling methods
    print(washing_machine.turn_on())   # Output: Washing Machine is now ON.
    print(washing_machine.turn_off())  # Output: Washing Machine is now OFF.
    

    Explanation:

    Abstract Base Class ('Appliance'):

    • 'Appliance' is an abstract class with abstract methods 'turn_on' and 'turn_off'.
    • These methods are intended to be implemented by any subclass of 'Appliance'.

    Instantiation of Abstract Class:

    • Attempting to instantiate the 'Appliance' class directly ('appliance = Appliance()') would result in a 'TypeError' because abstract classes cannot be instantiated.

    Derived Class ('WashingMachine'):

    • 'WashingMachine' inherits from Appliance and provides concrete implementations of the 'turn_on' and 'turn_off' methods.
    • The methods return strings indicating whether the washing machine is on or off.

    Method Calls:

    • The 'turn_on' and 'turn_off' methods are called on the 'WashingMachine' instance, showing how the abstract methods are implemented and used in practice.

    Summary:

    • Abstraction In Python is a way to define a common interface for a group of related classes. This ensures that all subclasses provide specific implementations for certain methods.
    • Abstract Classes: Created using the "ABC" module, abstract classes cannot be instantiated and may contain abstract methods that must be implemented by any subclass.
    • Interfaces: Python doesn’t have interfaces as a built-in concept, but abstract classes with only abstract methods can act as interfaces.
    • Key Benefits:
      • Code Consistency: Ensures that all subclasses adhere to a common structure.
      • Code Flexibility: Allows different subclasses to implement the common interface in their own way.

    By using abstraction, we can create more organized, maintainable, and extensible code, where the details of implementation are hidden, and a clear interface is provided for interaction with different objects.

    

    Become a Patron!

    Follow us on Facebook and Twitter for latest update.