Thuật ngữ polymorphism đề cập đến một hàm hoặc phương thức có nhiều dạng khác nhau trong các ngữ cảnh khác nhau. Vì Python là một ngôn ngữ kiểu động, nên tính đa hình trong Python được triển khai rất dễ dàng.
Nếu một phương thức trong lớp cha được ghi đè với logic kinh doanh khác nhau trong các lớp con khác nhau, thì phương thức của lớp cơ sở là một phương thức đa hình.
Có bốn cách để triển khai tính đa hình trong Python −
Duck typing là một khái niệm trong đó kiểu hoặc lớp của một đối tượng ít quan trọng hơn các phương thức mà nó định nghĩa. Sử dụng khái niệm này, bạn có thể gọi bất kỳ phương thức nào trên một đối tượng mà không cần kiểm tra kiểu của nó, miễn là phương thức đó tồn tại.
Thuật ngữ này được định nghĩa bởi một câu nói rất nổi tiếng rằng: Giả sử có một con chim đi như một con vịt, bơi như một con vịt, trông như một con vịt và kêu như một con vịt, thì có lẽ nó chính là một con vịt.
Trong đoạn mã dưới đây, chúng ta đang thực hiện việc minh họa khái niệm duck typing.
class Duck: def sound(self): return "Quack, quack!" class AnotherBird: def sound(self): return "I'm similar to a duck!" def makeSound(duck): print(duck.sound()) # creating instances duck = Duck() anotherBird = AnotherBird() # calling methods makeSound(duck) makeSound(anotherBird)
Khi bạn thực thi mã này, nó sẽ tạo ra đầu ra sau đây −
Quack, quack! I'm similar to a duck!
Trong ghi đè phương thức , một phương thức được định nghĩa trong một lớp con có cùng tên với một phương thức trong lớp cha của nó nhưng thực hiện một chức năng khác.
Như một ví dụ về tính đa hình được đưa ra dưới đây, chúng ta có shape là một lớp trừu tượng. Nó được sử dụng làm lớp cha bởi hai lớp circle và rectangle. Cả hai lớp đều ghi đè phương thức draw() của lớp cha theo những cách khác nhau.
from abc import ABC, abstractmethod class shape(ABC): @abstractmethod def draw(self): "Abstract method" return class circle(shape): def draw(self): super().draw() print ("Draw a circle") return class rectangle(shape): def draw(self): super().draw() print ("Draw a rectangle") return shapes = [circle(), rectangle()] for shp in shapes: shp.draw()
Khi bạn chạy đoạn mã trên, nó sẽ tạo ra đầu ra sau:
Draw a circle Draw a rectangle
Biến shp đầu tiên tham chiếu đến đối tượng hình tròn và gọi phương thức draw() từ lớp hình tròn. Trong lần lặp tiếp theo, nó tham chiếu đến đối tượng hình chữ nhật và gọi phương thức draw() từ lớp hình chữ nhật. Do đó, phương thức draw() trong lớp hình là đa hình.
Giả sử bạn đã tạo ra một lớp Vector để đại diện cho các vector hai chiều, điều gì sẽ xảy ra khi bạn sử dụng toán tử cộng để cộng chúng? Rất có thể Python sẽ báo lỗi với bạn.
Tuy nhiên, bạn có thể định nghĩa phương thức __add__ trong lớp của bạn để thực hiện phép cộng vector và sau đó toán tử cộng sẽ hoạt động như mong đợi.
class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2,10) v2 = Vector(5,-2) print (v1 + v2)
Khi đoạn mã trên được thực thi, nó sẽ tạo ra kết quả sau −
Vector(7,8)
Khi một lớp chứa hai hoặc nhiều phương thức có cùng tên nhưng khác nhau về số lượng tham số, thì tình huống này được gọi là nạp chồng phương thức (method overloading).
Python không cho phép nạp chồng các phương thức theo mặc định, tuy nhiên, chúng ta có thể sử dụng các kỹ thuật như danh sách đối số có độ dài thay đổi, đa phân phối và tham số mặc định để đạt được điều này.
Trong ví dụ sau, chúng ta sử dụng danh sách đối số có độ dài biến để đạt được tính năng nạp chồng phương thức.
def add(*nums): return sum(nums) # Call the function with different number of parameters result1 = add(10, 25) result2 = add(10, 25, 35) print(result1) print(result2)
Khi đoạn mã trên được thực thi, nó sẽ tạo ra kết quả sau −
35 70