Đa kế thừa (multiple inheritance) trong Python

Đây là bài 35/54 bài của series môn học Ngôn ngữ lập trình Python

1. Đa kế thừa (multiple inheritance) trong Python

Một lớp con có thể kế thừa từ nhiều hơn một lớp cha. Đó gọi là đa kế thừa (multiple inheritance). Tất cả các thuộc tính và phương thức của tất cả lớp cho được kế thừa bởi lớp con.

class Base1:
  pass

class Base2:
  pass

class MultiDerived(Base1, Base2):
  pass
Minh họa multiple inheritance trong Python
class Person:
  def info(self):
    print("Info of a person.")

class Employee:
  def showSalary(self):
    print("Salary of an employee.")

class Teacher(Person, Employee):
  pass

john = Teacher()
john.info()
john.showSalary()
Kết quả
Info of a person.
Salary of an employee.

Trong ví dụ trên, lớp Teacher kế thừa từ lớp PersonEmployee. Lớp Teacher sẽ kế thừa và sử dụng các phương thức info()showSalary() từ 2 lớp trên.

2. Method Resolution Order (MRO) trong Python

Có trường hợp các lớp cha có những phương thức cùng tên với nhau và lớp con gọi những phương thức này. Vậy thì phương thức của lớp cha nào sẽ được thực thi khi lớp con gọi đến?

Minh họa Method Resolution Order (MRO) trong Python

Python sử dụng Method Resolution Order (MRO) để quy định phương thức được gọi trong trường hợp này. MRO chỉ ra một thứ tự lớp nào được ưu tiên tìm và gọi phương thức trước. Chúng ta có thể sử dụng thuộc tính __mro__ hoặc hàm mro() để xem thứ tự này.

class Person:
  def info(self):
    print("Info of a person.")
  def work(self):
    print("A person works.")

class Employee:
  def work(self):
    print("An employee works.")
  def showSalary(self):
    print("Salary of an employee.")

class Teacher(Person, Employee):
  pass

print(Teacher.__mro__)
john = Teacher()
john.work()
Kết quả
(<class '__main__.Teacher'>, <class '__main__.Person'>, <class '__main__.Employee'>, <class 'object'>)
A person works.

Trong ví dụ trên, lớp Person được ưu tiên tìm hàm work() để thực thi trước do thứ tự kế thừa class Teacher(Person, Employee).

class Person:
  def info(self):
    print("Info of a person.")
  def work(self):
    print("A person works.")

class Employee:
  def work(self):
    print("An employee works.")
  def showSalary(self):
    print("Salary of an employee.")

class Teacher(Employee, Person):
  pass

print(Teacher.mro())
john = Teacher()
john.work()
Kết quả
(<class '__main__.Teacher'>, <class '__main__.Employee'>, <class '__main__.Person'>, <class 'object'>)
An employee works.

Trong ví dụ trên, lớp Employee được ưu tiên tìm hàm work() để thực thi trước do thứ tự kế thừa class Teacher(Employee, Person).

Lưu ý: Tất cả các lớp được tạo ra trong Python đều tự động kế thừa từ lớp object.

3. Kế thừa nhiều cấp (multilevel inheritance) trong Python

Chúng ta cũng có thể tạo ra một lớp mới bằng cách kế thừa từ một lớp con. Đó gọi là kế thừa nhiều cấp (multilevel inheritance). Python không giới hạn số cấp kế thừa.

Minh họa multilevel inheritance trong Python

Trong multilevel inheritance, tất cả thuộc tính và phương thức của lớp cha và lớp con sẽ được kế thừa bởi lớp con mới.

class Base:
  def methodBase(self):
    print("This is a method of Base.")

class Derived1(Base):
  def methodDerived1(self):
    print("This is a method of Derived1.")

class Derived2(Derived1):
  def methodDerived2(self):
    print("This is a method of Derived2.")

# create an object of Derived2
obj = Derived2()
# call method inherits from Base
obj.methodBase()
# call method inherits from Derived1
obj.methodDerived1()
# call method of Derived2
obj.methodDerived2()
Kết quả
This is a method of Base.
This is a method of Derived1.
This is a method of Derived2.

Trong ví dụ trên, lớp Derived1 kế thừa lớp Base. Lớp Derived2 kế thừa lớp Derived1. Lớp Derived2 sẽ kế thừa tất cả thuộc tính và phương thức của lớp BaseDerived1.

4. Hàm __init__() trong đa kế thừa

Trong đa kế thừa trong Python, lớp con sẽ kế thừa hàm __init__() của các lớp cha. Khi tạo một đối tượng của lớp con, hàm __init__() nào sẽ được gọi? Như chúng ta đã biết, Python sẽ sử dụng Method Resolution Order (MRO) để giải quyết vấn đề này. Nhưng khi đó, có một vấn đề xảy ra. Chúng ta cùng xem ví dụ sau đây để thấy rõ vấn đề này.

class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  def info(self):
    print(self.name + ",", self.age, "years old.")

class Employee:
  def __init__(self, salary):
    self.salary = salary

  def showSalary(self):
    print("salary:", self.salary)

class Teacher(Person, Employee):
  pass

print(Teacher.mro())
john = Teacher("John", 35)
# call method inherits from Person
john.info()
# AttributeError: 'Teacher' object has no attribute 'salary'
john.showSalary()
Kết quả
[<class '__main__.Teacher'>, <class '__main__.Person'>, <class '__main__.Employee'>, <class 'object'>]
John, 35 years old.
Traceback (most recent call last):
  File "c:\python-examples\main.py", line 20, in <module>
    john.showSalary()
  File "c:\python-examples\main.py", line 13, in showSalary
    print("salary:", self.salary)
AttributeError: 'Teacher' object has no attribute 'salary'

Vấn đề ở đây là hàm __init__() sử dụng để tạo ra một object của lớp Teacher là được kế thừa từ lớp Person. Lúc này, các thuộc tính của đối tượng có được chỉ là nameage được kế thừa từ lớp Person mà không có thuộc tính salary từ lớp Employee. Giải pháp trong những trường hợp này là định nghĩa hàm __init__() cho lớp Teacher.

class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  def info(self):
    print(self.name + ",", self.age, "years old.")

class Employee:
  def __init__(self, salary):
    self.salary = salary

  def showSalary(self):
    print("salary:", self.salary)

class Teacher(Person, Employee):
  def __init__(self, name, age, salary):
    super().__init__(name, age)
    self.salary = salary

# create an object of Teacher with it's __init__() function
john = Teacher("John", 35, "5000000")
# call method inherits from Person
john.info()
# call method inherits from Employee
john.showSalary()
Kết quả
John, 35 years old.
salary: 5000000

Trong ví dụ trên, chúng sử dụng câu lệnh super().__init__(name, age) để gọi hàm khởi tạo của lớp cha Person. Sau đó, chúng ta thêm thuộc tính salary cho các object của Teacher.

5/5 - (1 bình chọn)
Bài trước và bài sau trong môn học<< Kế thừa (inheritance) trong PythonTính đóng gói (encapsulation) và đa hình (polymorphism) trong Python >>
Chia sẻ trên mạng xã hội:

Để lại một bình luận

Lưu ý:

1) Vui lòng bình luận bằng tiếng Việt có dấu.

2) Khuyến khích sử dụng tên thật và địa chỉ email chính xác.

3) Mọi bình luận trái quy định sẽ bị xóa bỏ.