DEV Community

Cover image for Duck Typing in Python
Renan Moura
Renan Moura

Posted on • Originally published at renanmf.com

Duck Typing in Python

If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.

Dynamic Typed languages like Python and JavaScript have an interesting characteristic of letting an object respond to a call according to the definitions of methods and attributes it has independently of its type.

This means that the type of the object, i.e, its own class, or the class it inherits from doesn't matter, the interpreter only cares about the interfaces of the object.

Code Example

class Duck:
    def quack_and_swim(self):
        print('quack and swim')

class Bird:
    def quack_and_swim(self):
        print('quack and swim')

class Frog:
    def ribbit_and_swim(self):
        print('ribbit and swim')

def check_duck(animal):
    animal.quack_and_swim()

if __name__ == '__main__':
    duck = Duck()
    bird = Bird()
    frog = Frog
    check_duck(duck)
    check_duck(bird)
    check_duck(frog)
Enter fullscreen mode Exit fullscreen mode

The output of the code above is:

quack and swim
quack and swim
Traceback (most recent call last):
  File "<stdin>", line 7, in <module>
  File "<stdin>", line 2, in is_duck
AttributeError: type object 'Frog' has no attribute 'quack_and_swim'
Enter fullscreen mode Exit fullscreen mode

The first and second objects duck and bird could successfully respond to the of quack_and_swim() while the frog object couldn't and throws an exception.

In terms of code, the classes Duck and Bird are not related at all, they don't share a parent class through inheritance, but they have the same interface for the function quack_and_swim().

The type of the object is not important, the interface of the object when you use it is what matters.

In the end, if the object behaves like a duck, for practical purposes, it is a duck, no matter what bird it is, as long as it has the right interface.

But what do we do about the thrown exception?

Since we don't check the type of the object or if it has certain attributes, the Pythonic way to handle any exception is to use a try/except block:

try:
    check_duck(frog)
except AttributeError as error:
    print(error)
Enter fullscreen mode Exit fullscreen mode

The treated exception above will output:


Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
NameError: name 'check_duck' is not defined
Enter fullscreen mode Exit fullscreen mode

So we always assume the object has the method or attribute we need, if it doesn't, we catch the exception with the try block and treat it accordingly.

If you had any trouble following this article, I recommend this series of articles about Object-Oriented Programming:

Also, consider reading Handling Exceptions in Python to learn more about how to deal with exceptions in Python.

Top comments (0)