Duck typing is a fundamental principle of Python, where an object is evaluated based on its behavior rather than its class hierarchy.
The term comes from the saying: "If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck." In Python, the behavior of an object (its interface) is more important than the class to which it belongs. This implements the principle of "duck typing" — behavior-based typing (structural typing).
It seems that duck typing offers maximum flexibility. However, this increases the number of hidden bugs: the program "breaks" only during runtime if an object does not support the required interface.
Instead of checking the type (using isinstance or type), write functions that attempt to call the required methods on the object, assuming that if it supports them, everything will work. In extreme cases, catch AttributeError or TypeError to handle unexpected objects.
Example:
def quack_and_walk(duck): duck.quack() duck.walk() class Robot: def quack(self): print("I can quack!") def walk(self): print("I am walking") quack_and_walk(Robot()) # everything will work!
Key features:
Is it possible to check the type in Python using isinstance and say that this is correct for duck typing?
No. Duck typing is precisely opposed to strict type checking. It is more correct to operate with the behavior of the object rather than its lineage.
Can duck typing be implemented using abstract base classes (ABC)?
Partially. Abstract classes introduce elements of static structure. Duck typing does not require declaring relationships — you simply need to implement the required methods. But with Python 3.8, the typing.Protocol module was introduced, which brings us closer to structural typing.
Can duck typing work with magical methods (len, getitem etc.)?
Yes. If an object implements the required method (len), it can be passed to functions like len(obj), and this will work using duck typing.
A developer writes a function that accepts anything with a run() method, without checking. An object without this method appears in the code — and the error occurs only at runtime.
Pros:
Cons:
Using duck typing but with try/except and interface documentation:
def run_task(obj): try: obj.run() except AttributeError: print("The object does not support running a task!")
Pros:
Cons: