🐍 Introduction to Duck Typing

In many programming languages like Java or C++, you must tell the computer what type (like integer, string, or class) your object is before you can use it. Python is different. It uses something called dynamic typing, which means it only checks the type of an object when the program is running, not before.

Duck typing goes one step further. It does not care about the exact type of the object at all. Instead, it only checks whether the object can perform the required actions. This is explained with the famous phrase:

“If it looks like a duck, swims like a duck, and quacks like a duck, then it must be a duck.”

In programming, this means: if an object has the methods and attributes that are expected, it does not matter what type or class the object really belongs to.

🦆 Example of Duck Typing

Let’s look at an example to make it clear:

class Duck:
    def quack(self):
        print("Quack!")

    def swim(self):
        print("Swimming in the pond...")

class Dog:
    def quack(self):
        print("I'm trying to quack like a duck!")

    def swim(self):
        print("Swimming in the pool...")

# A function that expects 'duck-like' behavior
def make_it_quack_and_swim(animal):
    animal.quack()
    animal.swim()

# Both Duck and Dog can be passed
make_it_quack_and_swim(Duck())
make_it_quack_and_swim(Dog())

Here, the function make_it_quack_and_swim() does not care whether the object is a Duck or a Dog. As long as the object has quack() and swim() methods, it works perfectly. This is duck typing in action.

🛠️ Duck Typing in Real Life Python

Duck typing is used in many parts of Python’s standard library:

  1. File-like objects: Any object that has read() and write() methods can be treated like a file. It does not need to be an actual file on disk.
  2. Iterables: Any object that has the __iter__() method can be used in a for loop. For example, lists, tuples, dictionaries, and even custom classes.
  3. Context managers: Any object that has __enter__() and __exit__() methods can be used inside a with statement.

Example:

class FileLike:
    def __init__(self):
        self.content = "Hello World"
    def read(self):
        return self.content

# Works because it behaves like a file
f = FileLike()
print(f.read())

Even though FileLike is not a real file, it still works like one because it has the read() method.

✅ Advantages of Duck Typing

⚠️ Potential Pitfalls

💡 Best Practices

Example with type hints:

from typing import Protocol

class Quackable(Protocol):
    def quack(self): ...
    def swim(self): ...

def make_it_quack_and_swim(animal: Quackable):
    animal.quack()
    animal.swim()

This way, tools like IDEs and linters can warn you if the wrong type of object is passed.

📌 Summary

Duck typing in Python focuses on what an object can do instead of what it is. This makes Python code flexible, simple, and powerful. Objects of different types can be used in the same way if they share the same behavior. However, since Python does not strictly enforce types, you need to be careful with testing and readability. By combining duck typing with type hints and good practices, you can write code that is both flexible and easy to understand.