【问题标题】:python multiple inheritance: avoid calling the constructors twice in diamond shapepython多重继承:避免以菱形调用构造函数两次
【发布时间】:2012-09-17 10:41:29
【问题描述】:

考虑以下代码:

class A(object):
    def __init__(self):
        print("A.__init__")
        super(A, self).__init__()          # 1
        print("A.__init__ finished")

class B(A):
    def __init__(self):
        print("B.__init__")
        super(B, self).__init__()          # 2
        print("B.__init__ finished")

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

class D(B, C):
    def __init__(self):
        print("D.__init__")
        print("Initializing B")
        B.__init__(self)                   # 3
        print("B initialized")
        print("Initializing C")
        C.__init__(self)                   # 4
        print("C initialized")
        print("D.__init__ finished")

D()

# D.__init__
# Initializing B
# B.__init__
# C.__init__
# A.__init__
# A.__init__ finished
# C.__init__ finished
# B.__init__ finished
# B initialized
# Initializing C
# C.__init__
# A.__init__
# A.__init__ finished
# C.__init__ finished
# C initialized
# D.__init__ finished

据我了解,算法如下:

D.__init__ at (3) -> B.__init__ -> 
-> super().__init__ -> (super of self.__class__).__init__ ->
-> C.__init__ (# why C?) -> super().__init__ -> 
-> A.__init__

D.__init__ at (4) -> C.__init__ ->
-> super().__init__ -> 
-> A.__init__

其实有三个问题:
1. 当selfD 的实例时,为什么super().__init__() 调用B.__init__ (at 2) 调用C.__init__
2.这种情况下如何避免两次调用C.__init__A.__init__
2.1 初始化当前类继承的所有类的正确方法是什么?

【问题讨论】:

    标签: python initialization multiple-inheritance super diamond-problem


    【解决方案1】:

    问:为什么当 self 是 D 的实例时,super().__init__() 调用 B.__init__(在 2 处)调用 C.__init__

    当你打电话时

    super(X, self).__init__
    

    Python 查找 the MRO self.__class__.mro()。然后它在 X 之后从 MRO 中的 next 类调用 __init__

    当 self 是 D 的实例时,self.__class__.mro()[D, B, C, A]。所以super(B, self).__init__() 调用C.__init__(self)


    问:初始化当前类继承自的所有类的正确方法是什么?

    D.__init__ 中也使用 super:

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

    【讨论】:

    • 我发布了一个简化的案例。实际的 B 类和 C 类具有不同的签名。
    • 是使用super的pitfalls之一。签名必须全部匹配,因为您无法控制 super 下一个调用哪些类的方法。作为对陷阱文章的平衡,另请阅读Hettinger's take on super()
    猜你喜欢
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 2013-07-05
    • 2014-10-11
    • 1970-01-01
    • 2013-11-01
    相关资源
    最近更新 更多