在python的多繼承中,父類的初始化順序遵循所謂方法解析順序(Method Resolution Order,MRO)的機制。python使用C3線性化算法來確定多繼承類的MRO:
1. 目標:創建一個一致的線性繼承順序,同時保持父類的相對順序和子類優先原則。
2. 子類優先:子類總是在其父類之前出現。從而子類可以重寫父類的方法或屬性。
3. 從左到右的順序:在多繼承類時,指定的父類順序決定了它們在 MRO 中的優先級,會首先查找靠左的父類中的方法或屬性。
4. 每個類只處理一次:確保在複雜的繼承體系中,每個類的方法或屬性只被考慮一次。
關於如下代碼:
class Base1: def __init__(self, a): self.a = a print("Base1 initialized", a) class Base2: def __init__(self, a): self.a = a print("Base2 initialized", a) class Child(Base1, Base2): def __init__(self, a=1, b=2): super(Child, self).__init__(a) super(Base1, self).__init__(b) # Base1.__init__(self, a) # Base2.__init__(self, b) c = Child()
其中Child類多繼承了Base1和Base2,而Base2和Base2都需要傳入一個參數。代碼中列舉了兩種方式來初始化Child類:
super:super(class, self).__init__(a)通過MRO的順序找到class在MRO中的下一個類來進行初始化。比如以上代碼中的super(Child, self).__init__(a),實際上是對Base1進行初始化,並保存到self中。super().__init__(a)與super(Child, self).__init__(a)效果相同。由於其中Base2是Base1在MRO中的下一個類,因此super(Base1, self).__init__(b)是將b傳入Base2對其進行初始化,並加載到self中。
顯式初始化:文中註釋的代碼class.__init__(self, a),通過顯式的方式對父類class進行初始化,此時Base1.__init__(self, a)就是將a傳入Base1對其進行初始化。這種方式相較於super更容易理解,但需要自行控制好初始化的順序。此外,這種方式可以無需把父類寫在子類的類名括號中,也能實現對父類方法和屬性的繼承。當然這實際上等於複製了父類的屬性和方法,而並沒有繼承的關係,從而不能利用到繼承關係的一些python特性,如isinstance()方法的調用等。
要查看某個類的MRO,可使用class.__mro__。