Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Inheritance and polymorphism

After this lesson: I can reuse code through inheritance and use polymorphism.

55 min lesson7 commandsEveryday Linux commands lab: the thirty commands engineers type from memory

Inheritance reuses a class, polymorphism shares a call

Inheritance lets one class reuse the code of another. Polymorphism means one method call does a different job depending on the object it is called on. Together they let you write one loop that works for many kinds of thing, such as every health check on a server.

By the end of this lesson

Note

I can reuse code through inheritance and use polymorphism.

Key words

WordWhat it means
Inheritancea class taking the attributes and methods of another
Superclassthe class that is inherited from, also called the parent
Subclassa class that inherits from another, also called the child
Overrideto replace an inherited method in a subclass
Polymorphismone call that behaves differently for different objects

The cells students fill in are left blank in this preview.

A subclass is a kind of its parent

Suppose a monitor runs several checks on a server. A disk check is a kind of check. So is an error count check. They all have a name and they all say ok or FAIL.

Write that shared part once in a parent class, Check. Each child class inherits it and adds only what is different. In Python you write the parent in brackets: class DiskCheck(Check).

The parent class Check

Code: python
class Check:
    def __init__(self, name):
        self.name = name

    def healthy(self, value):
        return True

    def report(self, value):
        if self.healthy(value):
            return self.name + ": ok"
        return self.name + ": FAIL"

Two subclasses of Check

Code: python
class DiskCheck(Check):
    def __init__(self, name, limit):
        super().__init__(name)
        self.limit = limit

    def healthy(self, value):
        return value < self.limit

class ErrorCheck(Check):
    def __init__(self, name, most):
        super().__init__(name)
        self.most = most

    def healthy(self, value):
        return value <= self.most

A subclass overrides a method to change it

The parent says every check is healthy. That is a placeholder. DiskCheck writes its own healthy, and Python uses that one for disk checks. This is overriding.

super().__init__(name) runs the parent's constructor, so the name is still stored once, in one place. Notice that report is never rewritten. It calls self.healthy, and self decides which version runs.

Make a folder for this lesson

Command
mkdir -p ~/oop2

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Go into it

Command
cd ~/oop2

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the classes to checks.py

Command
printf 'class Check:\n    def __init__(self, name):\n        self.name = name\n\n    def healthy(self, value):\n        return True\n\n    def report(self, value):\n        if self.healthy(value):\n            return self.name + ": ok"\n        return self.name + ": FAIL"\n\nclass DiskCheck(Check):\n    def __init__(self, name, limit):\n        super().__init__(name)\n        self.limit = limit\n\n    def healthy(self, value):\n        return value < self.limit\n\nclass ErrorCheck(Check):\n    def __init__(self, name, most):\n        super().__init__(name)\n        self.most = most\n\n    def healthy(self, value):\n        return value <= self.most\n' > checks.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run one disk check and one error check

Command
python3 -c "from checks import DiskCheck, ErrorCheck; print(DiskCheck('disk', 90).report(95)); print(ErrorCheck('errors', 5).report(3))"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Polymorphism is one call, many behaviours

Look at the loop below. It calls item.report(50) on a list that holds three different kinds of object. The loop never asks which kind. Each object runs its own healthy.

That is polymorphism. You can add a fourth kind of check and the loop does not change.

One loop over three kinds of check

Code: python
from checks import Check, DiskCheck, ErrorCheck

items = [Check("plain"), DiskCheck("disk", 90), ErrorCheck("errors", 5)]
for item in items:
    print(item.report(50))

Write the loop to demo2.py

Command
printf 'from checks import Check, DiskCheck, ErrorCheck\n\nitems = [Check("plain"), DiskCheck("disk", 90), ErrorCheck("errors", 5)]\nfor item in items:\n    print(item.report(50))\n' > demo2.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run it

Command
python3 demo2.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Worked example: the value 50 for each check

ObjectTest it runsResult for 50Printed
Check("plain")always healthyTrueplain: ok
DiskCheck("disk", 90)50 < 90Truedisk: ok
ErrorCheck("errors", 5)50 <= 5Falseerrors: FAIL

The cells students fill in are left blank in this preview.

Ask whether an object is a Check

Command
python3 -c "from checks import Check, DiskCheck; d = DiskCheck('disk', 90); print(isinstance(d, Check), isinstance(Check('x'), DiskCheck))"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A common mistake

Warning

Many people think inheritance is the way to share code between any two classes. It fits only when the child really is a kind of its parent. A DiskCheck is a Check. Sharing a few lines is a weak reason, and the next lesson shows a better tool.

About this lab and its source: Everyday Linux commands lab: the thirty commands engineers type from memory

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.