Duck typing and interfaces
Imagine you’re playing a game where you have different toys: a toy car, a toy boat, and a toy airplane. They all have something in common: you can play with them. You don’t care if it’s a car, a boat, or a plane; as long as it can be played with, it’s a toy to you.
This is similar to how duck typing works in Python. The name “duck typing” 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, if an object can perform the required actions (methods), then it can be used, regardless of what type of object it actually is.
Example of Duck Typing
Let’s look at a simple example:
class Dog:
def sound(self):
return "Bark!"
class Cat:
def sound(self):
return "Meow!"
def make_sound(animal):
print(animal.sound())
dog = Dog()
cat = Cat()
make_sound(dog) # Output: Bark!
make_sound(cat) # Output: Meow!
In this example, both the ‘Dog
‘ and ‘Cat
‘ classes have a ‘sound
‘ method. The ‘make_sound
‘ function doesn’t care whether it’s dealing with a dog or a cat; it just calls the sound
method. As long as the object passed to it has a ‘sound
‘ method, it works.
Introduction to Interfaces
Now, let’s talk about interfaces. An interface is like a promise that certain methods will be present in a class. It’s like a checklist that classes have to follow. Python doesn’t have formal interfaces like some other programming languages, but we can create similar structures using abstract base classes (ABCs).
An abstract base class is a class that can’t be instantiated on its own and requires subclasses to implement certain methods.
Example of an Interface Using Abstract Base Classes
Let’s create an interface for an animal that has to have a ‘sound
‘ method:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
class Dog(Animal):
def sound(self):
return "Bark!"
class Cat(Animal):
def sound(self):
return "Meow!"
# This will work
dog = Dog()
cat = Cat()
print(dog.sound()) # Output: Bark!
print(cat.sound()) # Output: Meow!
# This will raise an error because Animal is an abstract class
# and can't be instantiated
# animal = Animal()
Here, ‘Animal'
is an abstract base class with an abstract method ‘sound
‘. Any subclass of ‘Animal
‘ must implement the ‘sound
‘ method.
Practice Questions
- Question: Create a class ‘
Bird
‘ that inherits from the ‘Animal
‘ abstract base class and implement the ‘sound
‘ method to return “Chirp!”.
Solution:
class Bird(Animal):
def sound(self):
return "Chirp!"
bird = Bird()
print(bird.sound()) # Output: Chirp!
- Question: Write a function ‘
animal_sounds
‘ that takes a list of ‘Animal
‘ objects and prints the sound of each one.
Solution:
def animal_sounds(animals):
for animal in animals:
print(animal.sound())
animals = [Dog(), Cat(), Bird()]
animal_sounds(animals)
# Output:
# Bark!
# Meow!
# Chirp!
- Question: Create a class ‘
Fish
‘ that should also inherit from ‘Animal
‘, but it should have a ‘sound
‘ method that returns “Blub!” and demonstrates it with the ‘animal_sounds
‘ function.
Solution:
class Fish(Animal):
def sound(self):
return "Blub!"
fish = Fish()
animals.append(fish)
animal_sounds(animals)
# Output:
# Bark!
# Meow!
# Chirp!
# Blub!
Duck typing and interfaces are powerful concepts in Python that allow for flexible and reusable code. Duck typing lets you use objects as long as they have the required methods, while interfaces (using abstract base classes) provide a way to define a contract that classes must follow. By understanding and using these concepts, you can write more robust and maintainable Python programs.