Duck typing is a variation of Dynamic Programming and uses a form of abductive reasoning for type checking. In this article, we will focus on the main intuition of duck typing and examples of ducking typing in python.
What is Duck Typing in Python? – Abductive Reasoning
The term duck arguably comes from the popular phrase:
“If it walks like a duck, and it quacks like a duck, then it is probably be a duck.”
The most important aspect of this phrase is, we don’t actually know if the object is a duck, we infer/reduce from a list of behaviour that the object is a duck. It is important to observe that we are not checking internally if the two objects are the same, but rather using known external behaviour to match the two objects.
This kind of reasoning can be transferred to the domain of computer science. In dynamic languages, there is no explicit type checking. But for certain use cases to makes sure the way a function behaves properly, it becomes important that the input type must be verified. This can cause various restrictions and design issues in terms of Dynamic Typing so Duck Typing was brought into the picture.
Duck typing gives more importance to the methods(behavior) defined inside the object, rather than the object itself. If the objects have the required methods, the object is allowed to pass. Let us see an example to understand this concept.
An example of Duck Typing
We define three classes representing different animals, a duck, a goose and a cat. They all produce different sounds. The Duck and Goose quack while the Cat makes a meow sound. Then we define a function quack() that takes in an animal and prints the description with the sound of a quack. It is obvious that an animal with no method of quack() will give an error when passed through the function, indicating a wrong type of variable( indicating it failed the duck test).
# Define the three classes class Duck: def quack(self): print("I am a duck and I quack.") class Goose: def quack(self): print("I am a goose and I quack.") class Cat: def meow(self): print("I am a dog and I meow.") # Define the method def quack(animal): animal.quack()
We pass the three animals and ask each of them to quack. While Duck and Goose quack, the Cat cannot quack and therefore throws an error.
quack(Duck()) quack(Goose()) quack(Cat())
Therefore we see that even though there is not external checking of object type, python knows this object does not support this function by checking the method compatibility.
A practical example of duck typing
One of the most used examples of duck typing is an iteration in python. Have you ever wondered how can you write a for loop with every iterable in python? Or in fact what makes an object iterable? Loops can be used on lists, numpy arrays, generator functions, Tensorflow/PyTorch data loaders, etc.
Duck typing comes into play here. No matter how different these objects are in terms of application, they are treated equally because of duck typing.
For iteration the class must have __iter__() and __next__() functions which makes it eligible for iterating. Python does not strongly type check these classes making it more and more flexible.
We can even define our own iterator for printing square numbers, where we define methods __iter__() and __next__() which are two methods called during python iteration.
class Squares: def __init__(self, l=0, u=-1): self.u = u self.n = l def __iter__(self): return self def __next__(self): if self.n < self.u: s = self.n ** 2 self.n += 1 return s else: raise StopIteration
for i in Squares(1, 4): print(i)
1 4 9
The support for duck typing in Python enables seamless integration of base python function with the user defined classes. This also allows interaction and integration between two different classes. We have seen an example of iterators in python, the concept can be applied to len() which duck checks if the object has __len__() method defined inside it. You can try various other other methods in python are explore how flexible python really is.