Inheritance
Inheritance allows you to create new classes built upon existing ones. By using inheritance, you can reuse methods and attributes from a parent class, which makes your code more modular and easier to maintain.
Basic Inheritance Concept
Think of it like a family tree:
- The parent class passes down traits to its children (e.g., attributes and methods, also known as "inherited traits")
- Each child can have its own unique traits in addition to the inherited ones (e.g., attributes and methods, also known as "unique traits")
- Children can pass down both their unique traits and their inherited traits to their own children
Creating a Child Class
To create a class that inherits from another, include the parent class name in parentheses when defining the child class:
class ParentClass:
# Parent class code here
pass
class ChildClass(ParentClass):
# Child class code here
pass
Let's see a simple example:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "Some generic animal sound"
class Dog(Animal):
def speak(self):
return "Woof!"
# Create an animal
generic_animal = Animal("Generic")
print(generic_animal.name) # Generic
print(generic_animal.speak()) # Some generic animal sound
# Create a dog
dog = Dog("Buddy")
print(dog.name) # Buddy (inherited from Animal)
print(dog.speak()) # Woof! (overridden in Dog)
In this example, Dog
inherits from Animal
. Notice that:
- We didn't have to define the
__init__
method inDog
- it's inherited fromAnimal
- The
Dog
class has access to thename
attribute defined inAnimal
- We've overridden the
speak
method inDog
to give it dog-specific behavior
The super()
Function
When you want to extend rather than completely replace a parent class's method, you can use the super()
function. This is especially important in the __init__
method to ensure the parent class is properly initialized:
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
# Call the parent's __init__ method
super().__init__(name)
# Add an attribute specific to Dog
self.breed = breed
# Create a dog
dog = Dog("Buddy", "Golden Retriever")
print(dog.name) # Buddy (initialized through Animal.__init__)
print(dog.breed) # Golden Retriever (initialized in Dog.__init__)
The super()
function calls the method from the parent class. In this case, super().__init__(name)
calls the __init__
method of the Animal
class, which sets up the name
attribute.
A Complete Example
Let's see a more complete example that demonstrates inheritance, method overriding, and using super()
:
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def make_sound(self):
return "Some generic animal sound"
def info(self):
return f"{self.name} is a {self.species}"
class Dog(Animal):
def __init__(self, name, breed):
# Initialize the parent class with name and species="Dog"
super().__init__(name, species="Dog")
# Add dog-specific attribute
self.breed = breed
# Override the make_sound method
def make_sound(self):
return "Woof!"
# Add a new method
def wag_tail(self):
return f"{self.name} wags tail happily!"
# Create an Animal
generic_animal = Animal("Generic", "Unknown")
print(generic_animal.info()) # Generic is a Unknown
print(generic_animal.make_sound()) # Some generic animal sound
# Create a Dog
buddy = Dog("Buddy", "Golden Retriever")
print(buddy.info()) # Buddy is a Dog
print(buddy.make_sound()) # Woof!
print(buddy.wag_tail()) # Buddy wags tail happily!
print(f"Buddy is a {buddy.breed}") # Buddy is a Golden Retriever
Extending Methods
Sometimes, you want to keep the functionality of a parent method and just add some additional behavior. You can do this by calling the parent method with super()
and then adding your own code:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"Hi, I'm {self.name} and I'm {self.age} years old."
class Student(Person):
def __init__(self, name, age, school):
super().__init__(name, age)
self.school = school
def introduce(self):
# Call the parent's introduce method
intro = super().introduce()
# Add student-specific information
return f"{intro} I attend {self.school}."
# Create a person
person = Person("John", 30)
print(person.introduce()) # Hi, I'm John and I'm 30 years old.
# Create a student
student = Student("Alice", 20, "Python University")
print(student.introduce()) # Hi, I'm Alice and I'm 20 years old. I attend Python University.
In this example, the Student
class doesn't completely override the introduce
method—it extends it by first calling the parent's method and then adding more information.
Multiple Inheritance
Python allows a class to inherit from multiple parent classes. This is called multiple inheritance:
class Flyable:
def fly(self):
return "Flying high!"
class Swimmable:
def swim(self):
return "Swimming gracefully"
# Inherit from both Flyable and Swimmable
class Duck(Flyable, Swimmable):
def quack(self):
return "Quack quack!"
# Create a duck
duck = Duck()
print(duck.fly()) # Flying high!
print(duck.swim()) # Swimming gracefully
print(duck.quack()) # Quack quack!
In this example, the Duck
class inherits from both Flyable
and Swimmable
, so it can both fly and swim. Multiple inheritance can be powerful, but it should be used with care as it can make your code more complex.
Checking Inheritance Relationships
Python provides built-in functions to check inheritance relationships:
class Animal:
pass
class Dog(Animal):
pass
dog = Dog()
# Check if dog is an instance of Dog
print(isinstance(dog, Dog)) # True
# Check if dog is also an instance of Animal
print(isinstance(dog, Animal)) # True
# Check if Dog is a subclass of Animal
print(issubclass(Dog, Animal)) # True
When to Use Inheritance
You should use inheritance when you have an "is-a" relationship between classes. For example:
- A dog is an animal
- A car is a vehicle
- A student is a person
If the relationship is more like "has-a", you might want to use composition (which we will cover in the next lesson) instead. For example:
- A car has an engine (not "a car is an engine")
- A person has a name (not "a person is a name")
Summary
Inheritance is a powerful feature that allows you to:
- Reuse code by having child classes inherit attributes and methods from parent classes
- Create specialized versions of classes by overriding methods
- Extend existing functionality by calling the parent method and adding your own code
- Model real-world relationships between objects
The basic syntax for inheritance in Python is:
class ParentClass:
# Parent class code
pass
class ChildClass(ParentClass):
# Child class code
pass
Remember to use super()
when you need to call a method from the parent class, especially in the __init__
method.