Duck typing là một khái niệm trong lập trình hướng đối tượng, nó được mô tả bởi câu nói “Nếu nó có hình dạng của một con vịt, thì nó là một con vịt”. Điều này có nghĩa là kiểu dữ liệu của một đối tượng không quan trọng, miễn là nó có các phương thức và thuộc tính tương tự như một đối tượng cụ thể mà chúng ta mong đợi.
Cú pháp khai báo: Trong Python, không có cú pháp khai báo đặc biệt cho duck typing. Tuy nhiên, để triển khai duck typing, bạn cần đảm bảo rằng các đối tượng truyền vào phương thức hoặc hàm có các phương thức và thuộc tính tương tự như nhau.
Ví dụ 1:
class Duck:
def quack(self):
print("Quack, quack")
class Person:
def quack(self):
print("I'm quacking like a duck!")
def make_quack(obj):
obj.quack()
duck = Duck()
person = Person()
make_quack(duck) # Output: Quack, quack
make_quack(person) # Output: I'm quacking like a duck!
Trong ví dụ này, chúng ta có hai lớp Duck
và Person
, mỗi lớp đều có phương thức quack()
. Hàm make_quack()
có thể nhận vào bất kỳ đối tượng nào có phương thức quack()
, bất kể kiểu dữ liệu của nó là gì. Vì vậy, chúng ta có thể truyền đối tượng của lớp Duck
và Person
vào hàm make_quack()
.
Ví dụ 2:
def calculate_total(items):
total = 0
for item in items:
total += item
return total
list1 = [1, 2, 3]
tuple1 = (4, 5, 6)
set1 = {7, 8, 9}
print(calculate_total(list1)) # Output: 6
print(calculate_total(tuple1)) # Output: 15
print(calculate_total(set1)) # Output: 24
Trong ví dụ này, chúng ta có một hàm calculate_total()
để tính tổng của các phần tử trong một đối tượng iterable. Hàm này có thể nhận bất kỳ đối tượng nào là iterable, bao gồm các đối tượng có kiểu dữ liệu khác nhau như list, tuple và set. Vì vậy, chúng ta có thể truyền các đối tượng có kiểu dữ liệu khác nhau vào hàm calculate_total()
.
Ví dụ 3:
Bạn có thể tưởng tượng một lớp Animal, mà các lớp con của nó như Cat, Dog, Fish,… sẽ kế thừa. Tuy nhiên, chúng ta cũng có thể tạo một lớp Person, mà nó không kế thừa từ lớp Animal nhưng có một phương thức là feed_pet() để cho thức ăn cho thú cưng. Nếu ta có một đối tượng thú cưng, có thể là một đối tượng Cat, Dog hoặc Fish, thì chúng ta có thể truyền đối tượng này vào hàm feed_pet() của lớp Person mà không cần phải kiểm tra kiểu đối tượng. Điều này là do Duck typing, vì đối tượng được xem như là một con vật có thể ăn, không quan trọng nó là loài gì.
Ví dụ code cho trường hợp này có thể như sau:
class Animal:
def eat(self):
print("Animal is eating")
class Cat(Animal):
def eat(self):
print("Cat is eating")
class Dog(Animal):
def eat(self):
print("Dog is eating")
class Fish(Animal):
def eat(self):
print("Fish is eating")
class Person:
def feed_pet(self, pet):
pet.eat()
cat = Cat()
dog = Dog()
fish = Fish()
person = Person()
person.feed_pet(cat) # Output: "Cat is eating"
person.feed_pet(dog) # Output: "Dog is eating"
person.feed_pet(fish) # Output: "Fish is eating"
Ở đây, lớp Person có phương thức feed_pet(), nhận một đối tượng thú cưng làm tham số đầu vào. Đối tượng thú cưng có thể là bất kỳ đối tượng nào kế thừa từ lớp Animal, nhưng không cần phải xác định kiểu đối tượng. Thay vào đó, phương thức feed_pet() chỉ cần gọi phương thức eat() của đối tượng thú cưng, và phương thức này được định nghĩa trong lớp con của lớp Animal. Khi chúng ta gọi phương thức feed_pet() với đối tượng cat, dog hoặc fish, phương thức eat() tương ứng của đối tượng sẽ được gọi.