【问题标题】:mixing super and classic calls in Python在 Python 中混合超级调用和经典调用
【发布时间】:2011-04-13 17:30:10
【问题描述】:

首先,让我引用“专家 Python 编程”一书中的一篇文章:

在以下示例中,使用 __init__ 方法调用其基类的 C 类将 让 B 类被调用两次!

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

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

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

print "MRO:", [x.__name__ for x in C.__mro__]  #prints MRO: ['C', 'A', 'B', 'object']
C()  #prints C A B B

最后,这里是对这里发生的事情的解释:

这是由于使用 C 实例进行的 A.__init__(self) 调用, 从而使 super(A, self).__init__() 调用 B 的构造函数。 换句话说, super 应该用于整个类层次结构。问题是有时 此层次结构的一部分位于第三方代码中。

我不知道为什么“super(A, self).__init__() 调用 B 的构造函数”。请解释一下这一刻。非常感谢。

【问题讨论】:

    标签: python


    【解决方案1】:

    要理解这种行为,您必须了解super 调用的不是基类,而是按照__mro__ 中的顺序搜索下一个匹配方法。因此,调用super(A, self).__init__() 会查看__mro__ == ['C', 'A', 'B', 'object'],将B 视为具有匹配方法的下一个类,并调用B 的方法(构造函数)。

    如果你把C改成

    class C(A,B):
        def __init__(self):
            print "C1"
            A.__init__(self)
            print "C2"
            B.__init__(self)
            print "C3"
    

    你得到

    MRO: ['C', 'A', 'B', 'object']
    C1
    A
    B
    C2
    B
    C3
    

    这显示了A 的构造函数如何调用B

    【讨论】:

    • 谢谢。一个问题 - 当“super(A, self).__init__()”在类 A 构造函数中被调用时,它的参数“self”是否等于我们刚刚实例化的 C 实例?
    • @varnie:是的。你可以在 A 的 __init__() 方法中 print super(A, self) 看到 self 确实是一个 C 实例。
    【解决方案2】:

    super 的文档说:

    返回一个代理对象,该对象将方法调用委托给该类型的父类或同级类。这对于访问已在类中重写的继承方法很有用。搜索顺序与 getattr() 使用的相同,只是跳过了类型本身。

    当您从C 中执行A.__init__(self) 时,super(A, self) 将返回<super: <class 'A'>, <C object>>。因为实例是C (<C object>),所以 C 继承层次结构中的所有类都被拾取。并且对所有这些都发出了__init__ 调用。因此,您会看到“B”被叫了两次。

    为了验证这一点,添加另一个类“Z”并让“C”也继承自“Z”。走着瞧吧。

    class Z(object):
        def __init__(self):
            print "Z"
            super(Z, self).__init__()
    
    class C(A, B, Z):    
        def __init__(self):
            print "C"
            A.__init__(self)
            B.__init__(self)
            Z.__init__(self)
    

    在这种情况下,A 将调用BZB 也将调用 Z

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-03
      • 1970-01-01
      • 1970-01-01
      • 2014-01-27
      • 2012-09-10
      • 1970-01-01
      相关资源
      最近更新 更多