Skip to main content

OOP: Inheritance

Subclasses, Method Overriding, and super()

· 3 min read

In the previous unit, we explored methods and the difference between class and instance variables. Now let's look at inheritance, which lets a class inherit attributes and methods from another class.

OOP: Inheritance

What Is Inheritance?

Inheritance creates a relationship between a parent class (also called a base class) and a child class (also called a derived class or subclass). The child class inherits everything from the parent, then can add new attributes and methods or change existing ones.

This promotes code reuse. Instead of copying code between similar classes, you define shared behavior in a parent class and let children inherit it.

Creating Subclasses

To create a subclass, put the parent class name in parentheses after the class name:

class Shape:
def describe(self):
print("This is a shape.")

class Square(Shape):
def describe(self):
print("This is a square.")

Square is a subclass of Shape. It inherits everything from Shape, but defines its own describe method that replaces the parent's version.

Overriding Methods

When a subclass defines a method with the same name as one in the parent class, the subclass version takes over. This is called overriding. When you call that method on a subclass object, Python runs the subclass version.

In the example above, calling describe() on a Square object prints "This is a square." The parent's version never runs.

The super() Function

Sometimes you want to extend a parent method rather than replace it entirely. The super() function lets you call the parent's version from within the child's method:

class Shape:
def describe(self):
print("This is a shape.")

class Square(Shape):
def describe(self):
super().describe()
print("More specifically, this is a square.")

Now calling describe() on a Square first runs the parent's describe(), printing "This is a shape.", then continues with the child's code, printing "More specifically, this is a square."

Project: Shape Subclasses

Let's build on our Shape class from previous units. We'll create Square and Triangle subclasses that each know how to draw themselves:

import turtle

class Shape:
def __init__(self, t, sides, length):
self.t = t
self.sides = sides
self.length = length

def draw(self):
pass # Subclasses will implement this

class Square(Shape):
def __init__(self, t, length):
super().__init__(t, 4, length)

def draw(self):
for _ in range(self.sides):
self.t.forward(self.length)
self.t.right(90)

class Triangle(Shape):
def __init__(self, t, length):
super().__init__(t, 3, length)

def draw(self):
for _ in range(self.sides):
self.t.forward(self.length)
self.t.right(120)

screen = turtle.Screen()
screen.setup(width=800, height=600)
screen.bgcolor("white")

t = turtle.Turtle()

shapes = [Square(t, 100), Triangle(t, 100)]

for shape in shapes:
shape.draw()
t.penup()
t.forward(150)
t.pendown()

t.hideturtle()
turtle.done()

The parent Shape class defines __init__ with three parameters. Each subclass simplifies its own __init__ to just take the turtle and length, then calls super().__init__() to set up the parent's attributes with the appropriate number of sides.

The parent's draw method uses pass as a placeholder. Each subclass overrides it with its specific drawing logic. The loop at the end treats all shapes the same way, calling draw() on each. This is the power of inheritance: define a common interface in the parent, then let each subclass implement its own behavior.

In the next unit, we'll explore encapsulation and polymorphism.