Polymorphism


Sometimes an object comes in many types or forms. If we have a button, there are many different draw outputs (round button, check button, square button, button with image) but they do share the same logic: onClick().  We access them using the same method . This idea is called Polymorphism.

Polymorphism is based on the greek words Poly (many) and morphism (forms).  We will create a structure that can take or use many forms of objects.

Polymorphism with a function:

We create two classes:  Bear and Dog, both  can make a distinct sound.  We then make two instances and call their action using the same method.

class Bear(object):
    def sound(self):
        print "Groarrr"
 
class Dog(object):
    def sound(self):
        print "Woof woof!"
 
def makeSound(animalType):
    animalType.sound()
 
 
bearObj = Bear()
dogObj = Dog()
 
makeSound(bearObj)
makeSound(dogObj)

Output:

Groarrr
Woof woof!

Polymorphism with abstract class (most commonly used)

polymorphism example
Polymorphism visual.
Abstract structure is defined in Document class.
If you create an editor you may not know in advance what type of documents a user will open (pdf format or word format?).  

Wouldn’t it be great to acess them like this,  instead of having 20 types for every document?

for document in documents:
    print document.name + ': ' + document.show()

To do so, we create an abstract class called document.  This class does not have any implementation but defines the structure (in form of functions) that all forms must have.   If we define the function show()  then both the PdfDocument and WordDocument must have the show() function. Full code:

class Document:
    def __init__(self, name):    
        self.name = name
 
    def show(self):             
        raise NotImplementedError("Subclass must implement abstract method")
 
class Pdf(Document):
    def show(self):
        return 'Show pdf contents!'
 
class Word(Document):
    def show(self):
        return 'Show word contents!'
 
documents = [Pdf('Document1'),
             Pdf('Document2'),
             Word('Document3')]
 
for document in documents:
    print document.name + ': ' + document.show()

Output:

Document1: Show pdf contents!
Document2: Show pdf contents!
Document3: Show word contents!

We have an abstract access point (document) to many types of objects (pdf,word) that follow the same structure.

Polymorphism example

polymorphism-example
Structure in abstract class, implementation in other classes
Another example would be to have an abstract class Car which holds the structure  drive() and stop().  

We define two objects Sportscar and Truck, both are a form of Car. In pseudo code what we will do is:

class Car:
    def drive abstract, no implementation.
    def stop abstract, no implementation.
 
class Sportscar(Car):
    def drive: implementation of sportscar
    def stop: implementation of sportscar
 
class Truck(Car):
    def drive: implementation of truck
    def stop: implementation of truck

Then we can access any type of car and  call the functionality without taking further into account if the form is Sportscar or Truck.  Full code:

class Car:
    def __init__(self, name):    
        self.name = name
 
    def drive(self):             
        raise NotImplementedError("Subclass must implement abstract method")
 
    def stop(self):             
        raise NotImplementedError("Subclass must implement abstract method")
 
class Sportscar(Car):
    def drive(self):
        return 'Sportscar driving!'
 
    def stop(self):
        return 'Sportscar breaking!'
 
class Truck(Car):
    def drive(self):
        return 'Truck driving slowly because heavily loaded.'
 
    def stop(self):
        return 'Truck breaking!'
 
 
cars = [Truck('Bananatruck'),
        Truck('Orangetruck'),
        Sportscar('Z3')]
 
for car in cars:
    print car.name + ': ' + car.drive()

Output:

Bananatruck: Truck driving slowly because heavily loaded.
Orangetruck: Truck driving slowly because heavily loaded.
Z3: Sportscar driving!

12 thoughts on “Polymorphism

  1. Crysis - July 25, 2015

    Isn’t there a way, in Python, to make a class “uninstantiable” like Java’s abstract keyword or something similar?

    1. Frank - July 25, 2015

      Yes, it’s possible to disable instantiation but it’s kinda unpythonic. That is to say, there is no abstract in Python.

      #!/usr/bin/env python3
       
      class Foo():
       
          def __init__(self):
              raise NotImplementedError()
       
      x = Foo()
      1. Sunny - July 11, 2016

        There is a module in Python called “abc”, which allows us to create Abstract classes, this will make class uninstantiable. See below example.

        import abc

        class Test(object):
        __metaclass__ = abc.ABCMeta
        .
        .

  2. Gilberto Trindade - July 1, 2015

    Hello, why using Polymorphism?
    Just to organize the code? If yes, Ok.
    Because we could write the code above as:

    class Sportscar:
        def __init__(self, name):
            self.name = name
        def drive(self):
            return 'Sportscar driving!'
     
        def stop(self):
            return 'Sportscar breaking!'
     
    class Truck:
        def __init__(self, name):
            self.name = name
        def drive(self):
            return 'Truck driving slowly because heavily loaded.'
     
        def stop(self):
            return 'Truck breaking!'
     
     
    cars = [Truck('Bananatruck'),
            Truck('Orangetruck'),
            Sportscar('Z3')]
     
    for car in cars:
        print(car.name + ': ' + car.drive())
    1. Frank - July 1, 2015

      Hi Gilberto, thanks for your comment! You are right it can be written that way. Polymorphism has many other uses than organizing the code.

      A few practical examples are:

      • the factory method. .
      • method thats accept an object of any type (of the defined abstraction)
      • lists of objects

      Let’s take the example of a method with different objects. We can then define a single function that accepts those types such that we only need to define one function instead of duplicating it:

      def startEngine(Car):
          print 'Starting engine of ' + Car.getName()

      Then:

      class Car:
          def __init__(self, name):    
              self.name = name
       
          def drive(self):             
              raise NotImplementedError("Subclass must implement abstract method")
       
          def stop(self):             
              raise NotImplementedError("Subclass must implement abstract method")
       
          def getName(self):
              return self.name
       
      class Sportscar(Car):
          def drive(self):
              return 'Sportscar driving!'
       
          def stop(self):
              return 'Sportscar breaking!'
       
      class Truck(Car):
          def drive(self):
              return 'Truck driving slowly because heavily loaded.'
       
          def stop(self):
              return 'Truck breaking!'
       
      def startEngine(Car):
          print 'Starting engine of ' + Car.getName()
       
      cars = [Truck('Bananatruck'),
              Truck('Orangetruck'),
              Sportscar('Z3')]
       
      for car in cars:
          startEngine(car)

      Output:

      Starting engine of Bananatruck
      Starting engine of Orangetruck
      Starting engine of Z3

      I hope you enjoy the site, feel free to ask anything, more tutorials coming soon 🙂

      1. Tinh Doan - September 17, 2015

        I don’t think so:

        class Sportscar:
            def __init__(self, name):
                self.name = name
            def drive(self):
                return 'Sportscar driving!'
         
            def stop(self):
                return 'Sportscar breaking!'
         
        class Truck:
            def __init__(self, name):
                self.name = name
            def drive(self):
                return 'Truck driving slowly because heavily loaded.'
         
            def stop(self):
                return 'Truck breaking!'
         
         
        cars = [Truck('Bananatruck'),
                Truck('Orangetruck'),
                Sportscar('Z3')]
         
        def printCarInfor(car):
            print car.name + ': ' + car.drive()
         
        for car in cars:
            printCarInfor(car)

        This way shows the same output

        1. Frank - September 17, 2015

          Hey hey!

          The difference is only the internal structure of the program. Polymorphism adds a layer of abstraction, it forces the methods of the classes/objects to exist.

  3. Yusuf - June 10, 2015

    This is the first example of Polymorphism I have seen, since I started learning Python OOP. Thanks

  4. Sagar - May 26, 2015

    what is significance of raise NotImplementedError in above example?
    i tried by putting null value to car[] or if i take method with null then i get syntax error but i am not getting above error use

    1. Frank - May 26, 2015

      It’s significant and should not be reachable. The idea is to use the Car class as abstraction, thus not creating objects from Car class. The car class should be seen as abstract class or interface, we define the methods but leave out all implementation.

      Let’s take a natural language example: if we create a car, it should have the ability to drive, start engine, accelerate and so on. How a car does this depends entirely on the type.

      By using polymorphism we can create new objects with various implementations, but with the same methods.

  5. Agustin - May 14, 2015

    So in this example, def makeSound is the definition of a regular function, not attached to any class?

    1. Frank - May 14, 2015

      Yes, it takes as input the object that has the same structure. It takes any object as long as it has those functions. In the example the object given as parameter to the function makeSound(), must have the function sound(). It will execute that function regardless of the actual implementation and accepts any object of the same form (structure).

      There is another form of polymorphism with an abstract class. I have extended this tutorial with more examples for you. If you have any further questions feel free to ask.