Python - Inheritance
Abstract Base Classes (ABCs) in Python are used to define abstract methods and ensure that specific methods are implemented in the subclasses. They provide a way to create a common interface for a group of related classes.
Let's consider an example to illustrate the role of Abstract Base Classes in Python inheritance:
from abc import ABC, abstractmethod
# Define an abstract base class (ABC)
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
# Create a concrete class that inherits from the Shape ABC
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def perimeter(self):
return 2 * 3.14 * self.radius
# Create another concrete class that inherits from the Shape ABC
class Square(Shape):
def __init__(self, side_length):
self.side_length = side_length
def area(self):
return self.side_length ** 2
def perimeter(self):
return 4 * self.side_length
# Attempt to create an instance of the abstract class (Shape)
try:
shape_instance = Shape() # This should raise a TypeError
except TypeError as e:
error_message = f"TypeError: {e}"
# Create instances of the concrete classes (Circle and Square)
circle_instance = Circle(radius=5)
square_instance = Square(side_length=4)
# Use the methods defined in the Shape ABC
circle_area = circle_instance.area()
circle_perimeter = circle_instance.perimeter()
square_area = square_instance.area()
square_perimeter = square_instance.perimeter()
print(error_message) # Output: TypeError: Can't instantiate abstract class Shape with abstract methods area, perimeter
print(circle_area) # Output: 78.5
print(circle_perimeter) # Output: 31.400000000000002
print(square_area) # Output: 16
print(square_perimeter) # Output: 16
In this example, the Shape
class is an abstract base class (ABC) that defines two abstract methods: area
and perimeter
. The concrete classes Circle
and Square
inherit from Shape
and provide implementations for these abstract methods.
The program demonstrates how ABCs help enforce a specific interface for related classes, ensuring that subclasses implement the required methods.
Output:
TypeError: Can't instantiate abstract class Shape with abstract methods area, perimeter 78.5 31.400000000000002 16 16
In Python, interfaces are not explicitly defined, but you can implement a similar concept using inheritance and abstract methods. Abstract methods in abstract base classes (ABCs) can serve as a way to define the interface that subclasses must adhere to.
Let's consider an example to illustrate how to implement interfaces using inheritance in Python:
from abc import ABC, abstractmethod
# Define an interface using an abstract base class (ABC)
class ShapeInterface(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
# Implement the interface in a concrete class
class Circle(ShapeInterface):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def perimeter(self):
return 2 * 3.14 * self.radius
# Create an instance of the concrete class
circle_instance = Circle(radius=5)
# Use the methods defined in the interface
circle_area = circle_instance.area()
circle_perimeter = circle_instance.perimeter()
print(circle_area) # Output: 78.5
print(circle_perimeter) # Output: 31.400000000000002
In this example, the ShapeInterface
class serves as an interface with two abstract methods: area
and perimeter
. The Circle
class inherits from ShapeInterface
and provides implementations for these abstract methods.
The program demonstrates how to implement interfaces using inheritance in Python. The abstract methods in the interface enforce a specific structure that subclasses must adhere to.
Output:
78.5 31.400000000000002
Composition is an object-oriented design principle where objects are composed of other objects, allowing for greater flexibility and code reuse. It promotes building objects by combining simpler, smaller objects rather than relying on inheritance hierarchies.
Let's consider an example to illustrate the use of composition as an alternative to inheritance in Python:
# Define a simple class representing a Engine
class Engine:
def start(self):
return "Engine started"
# Define another class representing a Car that uses composition
class Car:
def __init__(self):
# Composition: Car has an Engine
self.engine = Engine()
def drive(self):
return f"Car is driving. {self.engine.start()}"
# Create an instance of the Car class
car_instance = Car()
# Use the methods defined in the composed objects
drive_result = car_instance.drive()
print(drive_result) # Output: Car is driving. Engine started
In this example, the Car
class does not inherit from the Engine
class. Instead, it contains an instance of the Engine
class as an attribute. This is an example of composition, where a complex object (Car
) is built by combining simpler objects (Engine
).
The program demonstrates how composition allows for code reuse and flexibility by assembling objects at runtime rather than relying on fixed inheritance relationships.
Output:
Car is driving. Engine started
Inheritance is a key feature of object-oriented programming that allows a new class to inherit attributes and behaviors from an existing class. This promotes code reuse, extensibility, and polymorphism.
Let's consider an example to illustrate the advantages of using inheritance in software design:
# Define a base class representing a Shape
class Shape:
def __init__(self, color):
self.color = color
def describe(self):
return f"A {self.color} shape"
# Define a derived class representing a Circle
class Circle(Shape):
def __init__(self, color, radius):
# Call the constructor of the base class using super()
super().__init__(color)
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
# Define another derived class representing a Square
class Square(Shape):
def __init__(self, color, side_length):
# Call the constructor of the base class using super()
super().__init__(color)
self.side_length = side_length
def area(self):
return self.side_length ** 2
# Create instances of the derived classes
circle_instance = Circle(color="red", radius=5)
square_instance = Square(color="blue", side_length=4)
# Use the methods and attributes from the base class and derived classes
circle_description = circle_instance.describe()
circle_area = circle_instance.area()
square_description = square_instance.describe()
square_area = square_instance.area()
print(circle_description) # Output: A red shape
print(circle_area) # Output: 78.5
print(square_description) # Output: A blue shape
print(square_area) # Output: 16
In this example, the Shape
class serves as a base class with a method describe
. The derived classes Circle
and Square
inherit from Shape
and extend its functionality by adding methods area
. Instances of the derived classes can use both the methods and attributes of the base class and their own additional methods.
The program demonstrates how inheritance facilitates code reuse and extensibility, allowing the creation of specialized classes that inherit and build upon the functionality of a more general base class.
Output:
A red shape 78.5 A blue shape 16