Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Python

super() hoạt động như thế nào với đa kế thừa (multiple inheritance) trong Python?

super() cho phép gọi phương thức của lớp cha trong đa kế thừa, tuân theo MRO (Method Resolution Order).

Đa kế thừa (Multiple Inheritance)

Một lớp con kế thừa từ nhiều lớp cha.

Ví dụ không dùng super()

class Father:
    fathername = ""
    def father(self):
        print(self.fathername)

class Mother:
    mothername = ""
    def mother(self):
        print(self.mothername)

class Child(Father, Mother):
    def parent(self):
        print("Father:", self.fathername)
        print("Mother:", self.mothername)

s1 = Child()
s1.fathername = "Srinivas"
s1.mothername = "Anjali"
s1.parent()
Father: Srinivas
Mother: Anjali

Ví dụ dùng super()

class Father:
    def __init__(self):
        self.fathername = ""
        print("Father __init__")

class Mother:
    def __init__(self):
        self.mothername = ""
        print("Mother __init__")

class Child(Father, Mother):
    def __init__(self):
        super().__init__()  # Gọi Father.__init__ theo MRO
        print("Child __init__")

s1 = Child()
s1.fathername = "Srinivas"
s1.mothername = "Anjali"
print("Father:", s1.fathername)
print("Mother:", s1.mothername)
Father __init__
Child __init__
Father: Srinivas
Mother: Anjali

MRO (Method Resolution Order)

Python dùng thuật toán C3 Linearization để xác định thứ tự tìm kiếm phương thức. Xem MRO của class:

print(Child.__mro__)
(, , , )

super().__init__() trong Child gọi Father.__init__ (lớp cha đầu tiên trong MRO). Nếu Father cũng dùng super(), nó sẽ gọi Mother.__init__.

Diamond Problem (Kế thừa kim cương)

class A:
    def __init__(self):
        print("A")
        super().__init__()

class B(A):
    def __init__(self):
        print("B")
        super().__init__()

class C(A):
    def __init__(self):
        print("C")
        super().__init__()

class D(B, C):
    def __init__(self):
        print("D")
        super().__init__()

D()
D
B
C
A

MRO của D: D -> B -> C -> A -> object. Mỗi __init__ được gọi đúng 1 lần nhờ super().

Best Practice

  • Luôn dùng super() trong __init__ khi có kế thừa.
  • Không gọi trực tiếp Father.__init__(self) (hardcoded) trừ khi cần thiết.
  • Hiểu MRO để tránh bug khó tìm.