10.1 Kế thừa từ nhiều lớp
Kế thừa đa hình trong Python cho phép một lớp kế thừa thuộc tính và phương thức từ hơn một lớp cha. Điều này mang lại sự linh hoạt cao và cho phép tái sử dụng mã, nhưng cũng có thể dẫn đến các cấu trúc phức tạp và xung đột tiềm ẩn.
Khả năng liệt kê năm lớp cha cho lớp của bạn mở rộng đáng kể khả năng của bạn và làm cho việc viết mã trở nên rất thuận tiện. Thực hiện điều này rất dễ dàng — chỉ cần liệt kê các lớp cha phân tách bằng dấu phẩy:
class Base1:
def method1(self):
print("Method1 from Base1")
class Base2:
def method2(self):
print("Method2 from Base2")
class Derived(Base1, Base2):
pass
obj = Derived()
obj.method1()
obj.method2()
Mọi thứ hoạt động như dự định — thật tuyệt.
Tuy nhiên, kế thừa đa hình có một số mặt phức tạp mà nhất định phải xem xét khi sử dụng nó. Hãy xem xét, cách mà nó hoạt động và cách tránh các vấn đề liên quan đến kế thừa đa hình.
10.2 Gọi phương thức có trong nhiều lớp cơ bản
Lớp có thể kế thừa thuộc tính và phương thức từ nhiều lớp cha được liệt kê trong ngoặc sau tên lớp. Và các thuộc tính và phương thức này có thể có tên giống nhau:
class Base1:
def method(self):
print("Method from Base1")
class Base2:
def method(self):
print("Method from Base2")
class Derived(Base1, Base2):
pass
obj = Derived()
obj.method() # đây là phương thức của ai được gọi?
Trong ví dụ này, lớp Derived kế thừa từ Base1 và Base2. Khi method() được gọi, Python sẽ chọn phương thức của lớp đầu tiên được liệt kê — Base1.
Nhưng điều này không rõ ràng lắm, đúng không? Và nếu ai đó thay đổi mã của lớp cơ bản, có thể làm hỏng toàn bộ logic ứng dụng, và bạn thậm chí không biết rằng có gì đó không ổn. Chỉ cần gọi một chút không đúng phương thức :)
10.3 Sử dụng super() với kế thừa đa hình
Một đặc điểm thú vị khác là gọi super() cho lớp cơ bản khi kế thừa đa hình.
Ví dụ:
class Base1:
def method(self):
print("Method from Base1")
super().method()
class Base2:
def method(self):
print("Method from Base2")
super().method()
class Derived(Base1, Base2):
def method(self):
print("Method from Derived")
super().method()
obj = Derived()
obj.method()
Nào? Kết quả trên màn hình sẽ là gì?
Method from Derived
Method from Base1
Hoặc
Method from Derived
Method from Base2
Tôi có bất ngờ cho bạn — kết quả sẽ là:
Method from Derived
Method from Base1
Method from Base2
Mã super().method() sẽ gọi phương thức method() của từng lớp cơ bản! Đây chính là những vấn đề mà tôi đã đề cập đến khi đề cập đầu tiên về kế thừa đa hình.
10.4 Kế thừa kiểu (Diamond)
Và cuối cùng, vấn đề cổ điển về kế thừa kiểu kim cương. Điều này dễ dàng chỉ ra qua ví dụ, hơn là mô tả:
Dạng mã có thể trông như thế này:
class A:
def method(self):
print("Method from A")
class B(A):
def method(self):
print("Method from B")
super().method()
class C(A):
def method(self):
print("Method from C")
super().method()
class D(B, C):
def method(self):
print("Method from D")
super().method()
obj = D()
obj.method()
Kết quả sẽ là:
Method from D
Method from B
Method from C
Method from A
Để ít nhất là định hướng trong kế thừa đa hình, bạn cần hiểu rõ, thứ tự mà Python tìm kiếm các trường và phương thức trong các lớp cha là gì. Chính về điều này bạn sẽ tìm hiểu trong bài giảng kế tiếp.
GO TO FULL VERSION