Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.
Đa kế thừa trong Python
Trong Python, đa kế thừa (Multiple Inheritance) là một tính năng mạnh mẽ cho phép một lớp con kế thừa từ nhiều lớp cha cùng một lúc, mang đến sự linh hoạt và khả năng mở rộng cao. Tuy nhiên, việc sử dụng đa kế thừa có thể dẫn đến những tình huống phức tạp khi các lớp cha có phương thức trùng tên. Để giải quyết vấn đề này, Python sử dụng một cơ chế gọi là thứ tự phân giải phương thức (Method Resolution Order - MRO), giúp xác định thứ tự mà các phương thức sẽ được gọi. Trong bài viết này, mình sẽ tìm hiểu cách hoạt động của đa kế thừa và MRO trong Python, cùng những ví dụ minh họa cụ thể.
Giới thiệu về đa kế thừa trong Python
Khi một lớp kế thừa từ một lớp cha, ta có khái niệm "kế thừa đơn" (Single Inheritance). Python cho phép một lớp kế thừa từ nhiều lớp cha cùng lúc, gọi là "đa kế thừa" (Multiple Inheritance). Điều này cho phép một lớp con có thể mở rộng chức năng từ nhiều lớp khác nhau.
Cú pháp để thực hiện đa kế thừa rất đơn giản, bạn chỉ cần liệt kê các lớp cha trong dấu ngoặc đơn () sau tên của lớp con, như ví dụ sau:
class ChildClass(ParentClass1, ParentClass2, ParentClass3): pass
Cú pháp này tương tự như việc liệt kê các tham số trong danh sách đối số của một hàm. Thay vì chỉ có một lớp cha, bạn có thể chỉ định nhiều lớp cha, ngăn cách nhau bằng dấu phẩy.
Bài viết này được đăng tại [free tuts .net]
Hãy cùng xem ví dụ dưới đây để hiểu rõ hơn cách hoạt động của đa kế thừa.
Ví dụ về đa kế thừa trong Python
Trước tiên, định nghĩa một lớp Car
có phương thức go()
:
class Car: def go(self): print('Đi tới')
Tiếp theo, định nghĩa lớp Flyable
với phương thức fly()
:
class Flyable: def fly(self): print('Bay lên')
Bây giờ, tạo một lớp FlyingCar
kế thừa từ cả hai lớp Car
và Flyable
:
class FlyingCar(Flyable, Car): pass
Vì FlyingCar
kế thừa từ cả Car
và Flyable
, nên nó có thể sử dụng lại các phương thức của hai lớp này. Bạn có thể gọi các phương thức go()
và fly()
trên một đối tượng của lớp FlyingCar
như sau:
if __name__ == '__main__': fc = FlyingCar() fc.go() fc.fly()
Kết quả đầu ra:
Đi tới Bay lên
Thứ tự phân giải phương thức (MRO) trong Python
Khi các lớp cha có cùng tên phương thức và lớp con gọi phương thức đó, Python sẽ sử dụng thứ tự phân giải phương thức (MRO - Method Resolution Order) để tìm kiếm phương thức đúng. Hãy xem ví dụ sau.
Trước tiên, thêm phương thức start()
vào các lớp Car
, Flyable
, và FlyingCar
. Trong phương thức start()
của lớp FlyingCar
, gọi phương thức start()
của super()
:
class Car: def start(self): print('Bắt đầu xe') def go(self): print('Đi tới') class Flyable: def start(self): print('Bắt đầu đối tượng bay') def fly(self): print('Bay lên') class FlyingCar(Flyable, Car): def start(self): super().start()
Sau đó, tạo một đối tượng từ lớp FlyingCar
và gọi phương thức start()
:
if __name__ == '__main__': car = FlyingCar() car.start()
Kết quả đầu ra:
Bắt đầu đối tượng bay
Như bạn có thể thấy, super().start()
đã gọi phương thức start()
của lớp Flyable
vì nó xuất hiện trước trong MRO của FlyingCar
.
Bạn có thể kiểm tra thứ tự phân giải phương thức của lớp FlyingCar
bằng cách sử dụng thuộc tính __mro__
:
print(FlyingCar.__mro__)
Kết quả:
(<class '__main__.FlyingCar'>, <class '__main__.Flyable'>, <class '__main__.Car'>, <class 'object'>)
Thứ tự tìm kiếm phương thức sẽ lần lượt đi từ FlyingCar
, Flyable
, Car
, và cuối cùng là lớp gốc object
.
Nếu bạn thay đổi thứ tự các lớp cha trong định nghĩa lớp FlyingCar
, thứ tự MRO sẽ thay đổi theo.
class FlyingCar(Car, Flyable): def start(self): super().start()
Với đoạn mã trên, khi gọi phương thức start()
, kết quả sẽ thay đổi như sau:
Start the Car
Thứ tự phân giải phương thức lúc này sẽ là:
(<class '__main__.FlyingCar'>, <class '__main__.Car'>, <class '__main__.Flyable'>, <class 'object'>)
Đa kế thừa và super()
trong Python
Hãy xem cách hàm super()
hoạt động với phương thức khởi tạo (__init__
) khi sử dụng đa kế thừa.
Trước tiên, thêm phương thức __init__
vào lớp Car
:
class Car: def __init__(self, door, wheel): self.door = door self.wheel = wheel def start(self): print('Bắt đầu xe') def go(self): print('Đi tới')
Tiếp theo, thêm phương thức __init__
vào lớp Flyable
:
class Flyable: def __init__(self, wing): self.wing = wing def start(self): print('Bắt đầu đối tượng bay') def fly(self): print('Bay lên')
Phương thức __init__
của hai lớp Car
và Flyable
nhận số lượng tham số khác nhau. Nếu lớp FlyingCar
kế thừa từ cả hai lớp này, phương thức __init__
của nó cần phải gọi đúng phương thức khởi tạo theo thứ tự phân giải phương thức (MRO).
Cuối cùng, thêm phương thức __init__
vào lớp FlyingCar
:
class FlyingCar(Flyable, Car): def __init__(self, door, wheel, wing): super().__init__(wing=wing) self.door = door self.wheel = wheel def start(self): super().start()
Với thứ tự phân giải phương thức là:
(<class '__main__.FlyingCar'>, <class '__main__.Flyable'>, <class '__main__.Car'>, <class 'object'>)
Phương thức super().__init__()
sẽ gọi phương thức khởi tạo của lớp Flyable
, vì vậy bạn cần truyền đối số wing
vào.
Tuy nhiên, lớp FlyingCar
không thể truy cập trực tiếp vào phương thức __init__
của lớp Car
, do đó bạn cần khởi tạo thủ công các thuộc tính door
và wheel
.
Kết bài
Đa kế thừa trong Python cung cấp tính linh hoạt bằng cách cho phép một lớp kế thừa từ nhiều lớp khác nhau, giúp tái sử dụng mã hiệu quả hơn. Tuy nhiên, để tránh xung đột phương thức giữa các lớp cha, Python sử dụng cơ chế MRO (Method Resolution Order) nhằm xác định thứ tự tìm kiếm và thực thi phương thức một cách hợp lý. Hiểu rõ cách hoạt động của MRO là chìa khóa để làm chủ được đa kế thừa, đảm bảo mã nguồn duy trì tính ổn định, rõ ràng và dễ bảo trì.