In this lesson, we will delve into the concept of inheritance in Python. This topic is essential for understanding how to create complex and reusable code by building relationships between classes and objects. By the end of this tutorial, you'll learn about:
Inheritance allows us to create a new class based on an existing one, inheriting its properties, methods, and behavior. The existing class acts as a parent class, while the new class is called the child class. Here's a simple example:
class Animal:
def __init__(self, name):
self.name = name
def make_sound(self):
print("The animal makes a sound.")
class Dog(Animal):
def make_sound(self):
print("Woof!")
# Instantiate a dog and call its method
my_dog = Dog("Rex")
my_dog.make_sound() # Output: Woof!
In this example, the Dog
class inherits from the Animal
class, and we have overridden the make_sound()
method in the Dog
class to print a specific sound that dogs make. This is known as method overriding.
Let's create a more complex example using inheritance to model a simple hierarchy of shapes in a graphics library.
class Shape:
def __init__(self, color):
self.color = color
def draw(self):
print("Drawing a shape with color:", self.color)
class Rectangle(Shape):
def __init__(self, color, width, height):
super().__init__(color) # Call the parent class's constructor
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, color, radius):
super().__init__(color) # Call the parent class's constructor
self.radius = radius
def area(self):
return 3.14 * (self.radius ** 2)
# Create and draw shapes
rectangle = Rectangle("red", 5, 10)
circle = Circle("blue", 7)
rectangle.draw() # Output: Drawing a shape with color: red
circle.draw() # Output: Drawing a shape with color: blue
print("Rectangle area:", rectangle.area()) # Output: Rectangle area: 50
print("Circle area:", circle.area()) # Output: Circle area: 153.87632307692746
In this example, we have created a Shape
parent class with basic properties and behavior for drawing shapes. Then, we have created two child classes, Rectangle
and Circle
, which inherit from the Shape
class and add their specific properties (width/height for Rectangle, radius for Circle) and methods (area()
method for both child classes).
What causes it: When you try to use a variable or function that hasn't been defined yet in the current scope.
class Dog:
def make_sound(): # Missing `self` argument
print("Woof!")
# Instantiating and calling the method will cause NameError
my_dog = Dog()
my_dog.make_sound()
Error message:
Traceback (most recent call last):
File "example.py", line 5, in <module>
my_dog.make_sound()
NameError: name 'self' is not defined
Solution: Add the self
argument to the method definition.
class Dog:
def make_sound(self): # Correct definition with `self` argument
print("Woof!")
Why it happens: The self
variable represents the current instance of the class and is required for all methods to have access to the object's attributes.
How to prevent it: Always include the self
argument in method definitions when writing new classes.
What causes it: When you try to use a method or property that doesn't exist in the current class, but its parent class has that method/property with a different implementation.
class Animal:
def make_sound(self):
print("The animal makes a sound.")
class Dog(Animal):
pass # No overriding of the `make_sound()` method in the Dog class
my_dog = Dog()
my_dog.make_sound() # Output: The animal makes a sound. (Even though we want it to print "Woof!")
Error message:
Traceback (most recent call last):
File "example.py", line X, in <module>
my_dog.make_sound()
TypeError: can't pickle local object 'Dog'
Solution: Override the method in the child class to provide a specific implementation.
class Dog(Animal):
def make_sound(self):
print("Woof!")
Why it happens: When you inherit from a parent class, all its methods and properties become available in the child class unless explicitly overridden or removed.
How to prevent it: Be mindful of which methods and properties you override in the child classes to ensure they have the desired behavior.
__init__()
method in both the parent and child classes to set initial values for attributes__init__
, __del__
, __str__
, etc.Next steps for learning:
- Learn about polymorphism and its benefits in Python
- Explore other OOP concepts, such as encapsulation, abstraction, and multiple inheritance