Inheritance in Python
Inheritance is one of the core principles of Object-Oriented Programming (OOP), and it allows one class (the child or subclass) to inherit the properties and behaviours (attributes and methods) of another class (the parent or superclass). This promotes code reuse and improves the maintainability and extensibility of software.
1. Basic Concept of Inheritance
When a subclass inherits from a superclass:
- The subclass automatically gains all the attributes and methods from the superclass.
- The subclass can extend or override the functionality of the superclass.
Example:
# Parent class (Base class)
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "Some generic sound"
# Child class (Derived class)
class Dog(Animal):
def __init__(self, name, breed):
# Call the parent class constructor using super()
super().__init__(name)
self.breed = breed
def speak(self):
return f"{self.name} barks."
# Creating objects
dog = Dog("Buddy", "Golden Retriever")
print(dog.speak()) # Output: Buddy barks.2. The super() Function
super()is used to call the methods of the parent class from the child class. It is particularly useful in the constructor method (__init__) when you need to initialize the parent class.
Example:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "Some generic sound"
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # Calls the __init__ method of the parent class
self.breed = breed
def speak(self):
return f"{self.name} barks"
# Create an instance of Dog
dog = Dog("Charlie", "Labrador")
print(dog.speak()) # Output: Charlie barksIn the example above:
- The
Dogclass inherits from theAnimalclass. - The
Dogclass usessuper().__init__(name)to initialize thenameattribute inherited from theAnimalclass.
3. Method Overriding in Inheritance
Method overriding occurs when a subclass defines a method with the same name as a method in the parent class, but with a different implementation.
This allows the subclass to provide its own specific functionality for methods inherited from the superclass.
class Animal:
def speak(self):
return "Animal makes a sound."
class Dog(Animal):
def speak(self): # Overriding the speak method of the parent class
return "Dog barks."
# Creating an object of Dog
dog = Dog()
print(dog.speak()) # Output: Dog barks.In this example:
- The
Dogclass overrides thespeakmethod of theAnimalclass to provide its own implementation.
4. Inheritance with Multiple Classes (Multiple Inheritance)
In Python, a class can inherit from multiple classes, which is called multiple inheritance. This allows a class to inherit attributes and methods from more than one parent class.
class Animal:
def speak(self):
return "Some sound"
class Mammal:
def walk(self):
return "Walking on land"
class Dog(Animal, Mammal): # Inheriting from both Animal and Mammal
def bark(self):
return "Barking"
dog = Dog()
print(dog.speak()) # Output: Some sound
print(dog.walk()) # Output: Walking on land
print(dog.bark()) # Output: BarkingIn this case:
- The
Dogclass inherits from both theAnimalandMammalclasses. - It has access to methods
speakfromAnimalandwalkfromMammal.
5. Inheritance and Access Modifiers
In Python, there are no strict access modifiers like in some other languages (e.g., private, protected). However, Python uses a naming convention to indicate the intended visibility of attributes and methods:
- Public members: No leading underscores (
attributeormethod). - Protected members: A single leading underscore (
_attribute). - Private members: A double leading underscore (
__attribute).
Accessing Private and Protected Attributes
- Private attributes can be accessed directly within the class, but they are not intended to be accessed from outside the class.
- Protected attributes are intended to be accessible from subclasses, but it’s a convention to treat them as private.
class Animal:
def __init__(self, name):
self.__name = name # Private attribute
self._species = "Mammal" # Protected attribute
def get_name(self):
return self.__name # Accessing private attribute via a method
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name)
self.breed = breed
def display_info(self):
return f"{self.get_name()} is a {self.breed}."
# Creating an object of Dog
dog = Dog("Buddy", "Golden Retriever")
print(dog.display_info()) # Output: Buddy is a Golden RetrieverIn this example:
- The
__nameattribute is private in theAnimalclass, so it cannot be accessed directly outside the class, but we use theget_namemethod to retrieve it. - The
_speciesattribute is protected, which means it’s meant to be accessed within the class or its subclasses, but it’s not strictly private.
6. Abstract Classes and Inheritance
An abstract class is a class that cannot be instantiated directly and typically contains abstract methods that must be implemented by subclasses. It provides a template for other classes to inherit from.
- To define an abstract class, you need to import the
abcmodule and use theABCclass as a base class, along with the@abstractmethoddecorator to mark methods as abstract.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
# The following will raise an error since Animal cannot be instantiated directly
# animal = Animal() # Error: Can't instantiate abstract class Animal with abstract methods speak
# Creating an instance of Dog (since it implements the speak method)
dog = Dog()
print(dog.speak()) # Output: Woof!7. Key Benefits of Inheritance
- Code Reusability: Subclasses can reuse code from the parent class.
- Extensibility: New features can be added to existing classes without modifying the original code.
- Maintainability: Changes to the parent class automatically propagate to subclasses.
- Polymorphism: Subclasses can provide different implementations of methods that have the same name, allowing for flexible behavior.