Inheritance is a fundamental concept in object-oriented programming that allows new child classes to be derived from existing parent classes. The child class inherits the attributes and methods of the parent, allowing code reuse and the creation of specialized classes.
This comprehensive Python programming guide will explain inheritance in detail, including key concepts like polymorphism and method overriding. Through clear explanations and annotated code examples, you will learn how to utilize inheritance in Python to design flexible, modular programs.
We will cover:
- The basics of inheritance and its benefits
- How to create parent and child classes in Python
- Inheriting attributes and methods from the parent
- The
super()
function for accessing inherited members - Method overriding for specialized method implementations
- Polymorphism and abstract base classes
- Multiple inheritance and the method resolution order
- Common applications and use cases for inheritance
By the end, you will have a strong grasp of leveraging inheritance to write concise, maintainable, and extensible Python code. The concepts can be applied to various domains like game development, web programming, machine learning, and more.
Inheritance Basics
Inheritance allows a new class to be defined that reuses, extends, and modifies the behavior of an existing class. The existing class is called the parent class or base class, and the new class is the child class or derived class.
class ParentClass:
# Parent class definition
class ChildClass(ParentClass):
# Child class inherits from ParentClass
The child class inherits the attributes and methods of the parent, so we can leverage all existing functionality without rewriting it. At the same time, we can override methods to provide specialized implementations in the child.
Key benefits of using inheritance in Python:
- Code reuse - Eliminates redundant code by inheriting common logic from the parent class.
- Extensibility - Child classes can override parent methods and extend capabilities.
- Modularity - Each class encapsulates specific behavior, separating concerns.
Creating Parent and Child Classes
To demonstrate inheritance, let’s start by defining a simple Vehicle
parent class with some attributes and methods:
class Vehicle:
def __init__(self, make, color, fuel_type):
self.make = make
self.color = color
self.fuel_type = fuel_type
def drive(self):
print("Driving the vehicle!")
def add_fuel(self, amount):
print(f"Added {amount} gallons of {self.fuel_type} fuel.")
This parent class initializes each vehicle with make
, color
and fuel_type
attributes in the constructor. It also contains drive()
and add_fuel()
methods that all vehicles need.
We can now create a child class Car
that inherits from Vehicle
:
class Car(Vehicle):
# Car class inherits from Vehicle
The Car
class will have access to all attributes and methods of Vehicle
. We can demonstrate this by instantiating Car
and calling the inherited drive()
method:
my_car = Car("Tesla", "red", "electric")
my_car.drive() # Inherited method
This outputs:
Driving the vehicle!
So the Car
instance can utilize the drive()
logic we defined in the parent Vehicle
class.
Inheriting Attributes and Methods
By default, all attributes and methods from the parent are inherited by child classes.
For example, we can access my_car
’s make
, color
and fuel_type
attributes inherited from Vehicle
:
print(my_car.make) # Tesla
print(my_car.color) # red
print(my_car.fuel_type) # electric
The child Car
class also inherits the add_fuel()
method:
my_car.add_fuel(25) # Method inherited from Vehicle
Outputs:
Added 25 gallons of electric fuel.
This demonstrates how inheriting from Vehicle
gives Car
access to pre-built attributes and methods, avoiding code duplication.
We can also define additional custom attributes and methods in the child class:
class Car(Vehicle):
num_wheels = 4
def lock_doors(self):
print("Doors locked!")
These are specific to Car
instances and not inherited from Vehicle
.
The super()
Function
The super()
function provides access to inherited methods that have been overridden in the child class. This allows you to leverage the inherited implementation when overriding a method.
For example, let’s override drive()
in Car
:
class Car(Vehicle):
def drive(self):
print("Driving the car!")
super().drive() # Call parent drive() method
Now when we call drive()
, it will print out the Car
custom string but still retain the core Vehicle
drive()
behavior:
my_car.drive()
Output:
Driving the car!
Driving the vehicle!
So super()
allows the inherited parent behavior to be reused even when overriding a method.
Method Overriding
Method overriding is the concept of redefining a method in the child class that already exists in the parent. This allows child classes to provide specialized implementations tailored to their needs.
Let’s modify the add_fuel()
method in Car
to be specific to electric vehicles:
class Car(Vehicle):
def add_fuel(self, kwh):
print(f"Charging battery with {kwh} kWh of electricity.")
When we call add_fuel()
, it will now use the Car
version instead of the parent Vehicle
one:
my_car.add_fuel(85)
Outputs:
Charging battery with 85 kWh of electricity.
Overriding methods like this allows child classes to specialize the inherited behavior.
Polymorphism and Abstract Base Classes
Polymorphism refers to a child class object being able to be treated like a parent class object, because they share attributes and methods.
For example, we can have a list containing different vehicle objects, and call drive()
polymorphically on each:
cars = [Car("Tesla", ...), Car("Toyota", ...)]
for vehicle in cars:
vehicle.drive()
This demonstrates polymorphic behavior - treating each child instance as its parent type.
To define common interfaces for a group of related classes, we can use abstract base classes (ABCs). An abstract method can be defined without implementation that child classes must override:
from abc import ABC, abstractmethod
class Vehicle(ABC):
@abstractmethod
def drive(self):
pass
class Car(Vehicle):
def drive(self):
print("Driving the car!")
Any child of Vehicle
must implement drive()
or an error occurs. This enforces a common interface.
Multiple Inheritance
Python supports multiple inheritance, where a class can inherit from multiple parent classes.
For example:
class GasVehicle(Vehicle):
# Fuel methods for gas vehicles
class ElectricVehicle(Vehicle):
# Charging methods for electric vehicles
class HybridCar(GasVehicle, ElectricVehicle):
# Hybrid cars inherit from both parent classes
The child HybridCar
class can access methods and attributes from both GasVehicle
and ElectricVehicle
.
The order of inheritance determines the method resolution order - the order methods are looked up in when called. Child classes precede parents, and the leftmost parent is checked first.
Common Applications of Inheritance
Some common use cases for leveraging inheritance in Python include:
- Defining graphical user interface (GUI) widget classes that extend base widget functionality.
- Modeling entities in a game like characters, vehicles, buildings etc. that have shared parent classes.
- Implementing specialized exception and error classes that inherit from base Python exceptions.
- Extending built-in Python data structures like dict and list to have custom versions with added functionality.
- Implementing machine learning algorithms where specialized models inherit reusable code from parent model classes.
Inheritance enables the “is-a” relationship between classes to reuse common logic in a hierarchy while allowing specialization as needed.
Conclusion
This guide provided a comprehensive overview of inheritance in Python. We covered key concepts like:
- Inheriting attributes and methods from a parent class
- Overriding inherited methods for custom child class logic
- Using
super()
to leverage inherited implementations - Polymorphism and abstract base classes
- Multiple inheritance and method resolution order
Inheritance is a powerful tool for extending class functionality in Python. Using it appropriately leads to code reuse, well-organized hierarchies, and maintainable programs.
The concepts can be applied across domains like game programming. web development, scientific computing and more. Mastering inheritance is an important milestone for any intermediate Python programmer.
There are many additional techniques and patterns related to inheritance that can be explored further, but this guide covers the core foundations you need to start utilizing inheritance effectively in your own Python projects.