Single Inheritance
Introduction
Single inheritance is a fundamental concept in object-oriented programming (OOP) that allows a class to inherit attributes and methods from a single parent class. This mechanism promotes code reuse and helps in creating a hierarchical structure of classes. In Python, single inheritance is straightforward to implement and widely used.
Basic Syntax
The basic syntax for single inheritance in Python is:
class ParentClass:
# Parent class code
class ChildClass(ParentClass):
# Child class code
The child class is defined by putting the name of the parent class in parentheses after the child class name.
Example: Animal Hierarchy
Let's explore single inheritance with a simple animal hierarchy:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
pass
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
# Usage
dog = Dog("Buddy")
cat = Cat("Whiskers")
print(dog.speak()) # Output: Buddy says Woof!
print(cat.speak()) # Output: Whiskers says Meow!
In this example:
Animal
is the parent class.Dog
andCat
are child classes that inherit fromAnimal
.- The
speak
method is overridden in each child class.
Inheriting and Extending Methods
Child classes can inherit methods from their parent class and can also extend or override them:
class Vehicle:
def __init__(self, brand):
self.brand = brand
def start(self):
return f"The {self.brand} vehicle is starting."
class Car(Vehicle):
def __init__(self, brand, model):
super().__init__(brand)
self.model = model
def start(self):
return f"{super().start()} It's a {self.model} model."
# Usage
vehicle = Vehicle("Generic")
car = Car("Toyota", "Corolla")
print(vehicle.start()) # Output: The Generic vehicle is starting.
print(car.start()) # Output: The Toyota vehicle is starting. It's a Corolla model.
Key points:
super()
is used to call methods from the parent class.- The
__init__
method ofCar
extends the parent's__init__
method. - The
start
method inCar
overrides and extends the parent'sstart
method.
Accessing Parent Class Attributes
Child classes can access attributes defined in the parent class:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"My name is {self.name} and I'm {self.age} years old."
class Student(Person):
def __init__(self, name, age, student_id):
super().__init__(name, age)
self.student_id = student_id
def introduce(self):
return f"{super().introduce()} My student ID is {self.student_id}."
# Usage
person = Person("Alice", 30)
student = Student("Bob", 20, "S12345")
print(person.introduce()) # Output: My name is Alice and I'm 30 years old.
print(student.introduce()) # Output: My name is Bob and I'm 20 years old. My student ID is S12345.
Method Resolution Order (MRO)
Python uses the Method Resolution Order (MRO) to determine the order in which it searches for methods and attributes in the inheritance hierarchy. For single inheritance, this is straightforward:
class A:
def method(self):
return "Method from A"
class B(A):
pass
class C(B):
pass
print(C.mro()) # Output: [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
The MRO shows the order in which Python will look for methods: first in C
, then in B
, then in A
, and finally in object
(the base class for all Python classes).
Best Practices
- Use Inheritance Judiciously: Inherit only when there's a clear "is-a" relationship between classes.
- Favor Composition Over Inheritance: When possible, use composition (has-a relationship) instead of inheritance for more flexible designs.
- Keep the Hierarchy Simple: Deep inheritance hierarchies can become complex and hard to maintain.
- Use
super()
Correctly: Always usesuper()
when calling methods from the parent class to ensure proper method resolution. - Document the Inheritance: Clearly document the purpose and expectations of inherited methods and attributes.
Conclusion
Single inheritance in Python is a powerful tool for creating hierarchical structures of classes, promoting code reuse, and implementing polymorphism. By understanding how to properly use inheritance, including method overriding and the use of super()
, you can create more organized, efficient, and maintainable code. Remember to use inheritance judiciously and always consider whether composition might be a better alternative for your specific use case.