Python: a simple introduction to inheritance

04 Mar 2012

In this post I will talk about inheritance in Python. In Object Oriented Programming, inheritance is one of the most important features. I will explain simple inheritance and multiple inheritance with some basic examples. Some beginners have angst to start with inheritance, but I want to show you in this post that it's not really that complicated and makes your life easier.

What is inheritance?

Object-Inheritance is a way to re-use existing code of existing Objects. An Object we inherit from is called a super type. An Object that inherits is called a subtype. When we subtype, we specify an Object like the super type, but define it more specific. This last part is very important, if you want good design, keep to these principles:

  • A sub type never implements less functionality than the super type
  • Inheritance should never be more than two levels deep

When do we use inheritance?

We use inheritance when we want to avoid redundant code. Take an animal for example, an animal has multiple characteristics, a lot are the same for every animal. If we simplify this down, lets say every animal:
  • has a name
  • has a type
  • sleeps
  • eats
  • makes a noise
So in our super class, we define all of these methods, because all of our Animals will use this behavior. When looking at the class below there is nothing special about it we wouldn't have in a regular Class.

class Animal(object):
    '''
    Our animal object
    '''
    def __init__(self,name,animalType):
        print "My name is ",name
        print "I am a ",animalType
    def makeNoise(self,noise):
        print noise
    def sleep(self):
        print "zzzzZZZZzzzzZZZ"
    def eat(self,food):
        print "Eating ",food

Now we let's say we will create a new Animal, but a more specific animal, like a Tiger. Our Tiger will inherit all of the methods of our Animal super type. To inherit we simply write instead of object in the class statement, Animal. (In fact all Classes by default already inherit from Object, this is not only so in Python but also in Java, but in Python we always state it explicitly). Let's have a look at the Class:

class Tiger(Animal):
    def __init__(self,name):
        super(Tiger,self).__init__(name,"Tiger")
        self.makeNoise("roar")
    def stalk(self):
        print "Stalking an antelope"
        self.eat("antelope meat")
tony = Tiger("Tony")
tony.stalk()
tony.sleep()

Let's break it down:

  • Create a class that inherits from Animal:

    class Tiger(Animal):
    

  • Call the constructor in the super class

    super(Tiger,self).__init__("Tony","Tiger")
    

  • Call in the Tigers constructor, a method from the super class (make the tiger roar)

     self.makeNoise("roar")
    

  • Define a method no other animal has (let's say only the Tiger stalks animals), then call the eat method of the super class where our Tiger eats the antelope method:

        def stalk(self):
            print "Stalking an antelope"
            self.eat("antelope meat")
    

  • Create a tiger called tony

    tony = Tiger("Tony")
    

  • After Tony is born let him stalk an animal(call the stalk method from the Tiger object)

    tony.stalk()
    

  • After Tony has eaten it's time for a nap (call the sleep method from the super class)

    tony.sleep()
    

Now let's create a Peacock:

class Peacock(Animal):
    def __init__(self,name):
        super(Peacock,self).__init__(name,"Peacock")
        self.makeNoise('CRIOOOUUUUUULLLL')
    def showTailFeathers(self):
        print "Look at them feathers"
peach = Peacock("Peach")
peach.eat("Wheat")
peach.showTailFeathers()
peach.sleep()

This class has basically the same functionality as the Tiger one, except the Peacock loves to eat wheat. If you want to redefine a method completely (like overriding in Java), you just need to redefine the method in the subtype. So let's say a peacock only eats wheat, but will also burp after eating, we can redefine the eat method in the peacock class:

    def eat(self):
        super(Peacock,self).eat("Wheat")
        print "burp"

Multiple Inheritance

Obviously our animals might have other characteristics they share with other animals, but which not every animal has. Some animals can fly, other animals can swim, other animals can do both. This is where multiple inheritance comes in. We just define these behaviors of swimming and flying into new objects and let the sub types inherit this behavior from the super type. Let's first define our swimming and flying classes:

class Fly(object):
        def __init__(self):
            print "I have the ability to fly!"
        def fly(self):
            print "I'm flying wiieeeeee"
class Swim(object):
        def __init__(self):
            print "I have the ability to swim!"
        def swim(self):
            print "I'm swimming like a boss"

Now let's create a Duck that will inherit properties from Animal,Fly and Swim:

class Duck(Animal,Fly,Swim):
        def __init__(self,name):
            super(Duck,self).__init__(name,"Duck")

Now as you might have noticed we have three init methods from our super classes. So how does python know which one to choose? Let's make a Duck object and find out!

daffy = Duck()
daffy.fly()
daffy.swim()

The output is:

My name is  Daffy
I am a  Duck
I'm flying wiieeeeee
I'm swimming like a boss

As you can see the only init method that was called was the Animal method. Python will look at the order in which the objects are placed when creating a class. The first one (most left) will get its init method called. If you want to call the other init methods, you will have to do it explicitly:

class Duck(Animal,Fly,Swim):
        def __init__(self,name):
            super(Duck,self).__init__(name,"Duck")
            Swim.__init__(self)
            Fly.__init__(self)

This goes for every other method as well.

Deeper inheritance

Now we can also do deeper inheritance, let's say we have a frog, a frog is an amphibian, but there are more amphibians than frogs, so we define an amphibian class. First add another class called WalkOnLand as well (I didn't add this to the Duck example to keep things less bombastic):

class WalkOnLand(object):
        def __init__(self):
            print 'I can walk on land'
        def walk(self):
            print "walking... and I hope you like walking too"

Now let's add an Amphibian class that inherits from WalkOnLand and Swim:

class Amphibian(Animal,Swim,WalkOnLand):
        def __init__(self,name,typeA):
            print "Im an amphibian,"
            super(Amphibian,self).__init__(name,typeA)
            Swim.__init__(self)
            WalkOnLand.__init__(self)

Now let's create a Frog from the Amphibian class:

class Frog(Amphibian):
    def __init__(self,name):
            super(Frog,self).__init__(name,"Frog")

If you now create a Frog it will say it's an amphibian, its name is kermit, it can swim and walk on land.

Final words

I hope this tutorial explains a bit more how inheritance works. There are some pitfalls with Inheritance. If you want to know more about them check Guido van Rossum's blog (creator of python). Also have a look at the diamond complex on wikipedia. If you are familiar with Inheritance in Java or C++ please read the next alinea as well. You can get the full source here on pastebin

Public,private and protected methods

If you are coming from another programming language, such as Java or C++, you might be wondering what the equivalent in Python is for protected,private and public methods. However these to do not exist in Python. It is because it makes little sense, if he wants to use a method that is private in some class, he will just open that source file and copy it. Therefor in Python they do not distinct between these methods. However there is a convention:
  • Public:

    def public(self)
    

  • Protected:

    def _protected(self)
    

  • Private:

    def __private(self)
    

This is a convention, so it is not enforced by the compiler!