Python language basics 82: polymorphism through inheritance II
February 27, 2016 Leave a comment
Introduction
In the previous post we looked at some theory behind inheritance. First we looked at the general meaning of the word ‘inheritance’ and then discussed its role in programming. We went through the basic terms such as superclasses, also knows as abstract classes or base classes, and derived classes.
In this post we’ll start building a simple example to make all of that clearer. If you’re have a background in strongly typed languages, like Java, then you’ll see that inheritance is implemented slightly differently in Python. However, the end result is much the same.
Classes with no inheritance
We’ll start off with two classes related to animals: Dog and Duck. We first build them with no inheritance in mind. We’ll then analyse what’s wrong with their class design and finally make them better.
We’ll keep the classes as simple as possible. First off we have the Dog class:
class Dog: def __init__(self, name, age): self._name = name self._age = age def make_sound(self): return "Woooff" def number_of_legs(self): return 4 def catch_intruders(self, number_of_intruders): print("Caught {} intruders!".format(number_of_intruders)) def describe_me(self): print("My name is {}, I am {} years old , I have {} legs. My language sounds as follows: {}".format(self._name, self._age, self.number_of_legs(), self.make_sound()))
We have a constructor with 2 parameters: name and age. Then we have 2 functions that return a sound and the number of legs respectively. Then there’s a method that describes how a dog successfully catches a number of intruders. Finally we have a function that describes the dog.
Here is an example of usage:
d = Dog("Elvis", 3) d.describe_me() d.catch_intruders(3)
Here’s the output:
My name is Elvis, I am 3 years old , I have 4 legs. My language sounds as follows: Woooff
Caught 3 intruders!
That’s simple so far, right?
Next let’s look at the Duck class:
class Duck: def __init__(self, name, age): self._name = name self._age = age def make_sound(self): return "Quack" def number_of_legs(self): return 2 def what_is_so_special(self): return "I am known for duck typing" def average_weight(self): return 3 def describe_me(self): print("My name is {}, I am {} years old , I have {} legs. My language sounds as follows: {}".format(self._name, self._age, self.number_of_legs(), self.make_sound()))
Example usage:
duck = Duck("Ducky", 4) duck.describe_me() print(duck.what_is_so_special()) print(str(duck.average_weight()))
…which produces the following output:
My name is Ducky, I am 4 years old , I have 2 legs. My language sounds as follows: Quack
I am known for duck typing
3
We’re done building the basics. Let’s go through a couple of observations:
- Both Dog and Duck have identical initialisers: they require a name and an age
- Both of them have a make_sound and number_of_legs functions but they are implemented differently
- Both have a describe_me method with identical implementations
- Both have unique functions not found in the other: the Dog has catch_intruders and the Duck has what_is_so_special and average_weight
We see that we have some common features and some code duplication across the two classes. However, they are independent classes so how can we resolve the situation?
We’ll see in the next post how base and derived classes are built in Python and how common functionality can be delegated to the base class.
Read all Python-related posts on this blog here.