继承:每次打电话给超级'?

时间:2017-05-26 15:15:23

标签: python

考虑以下代码:

class A:
    def __init__(self):
        print('class A is being constructed')

    def print_msg(self):
        print('Hello, I am class A')

class B(A):
    def __init__(self):
        super(B, self).__init__()
        print('class B is being constructed')

    def print_msg(self):
        super(B, self).print_msg()
        print('Hello, I am class B')

如您所见,每次调用super(B, self)时都会调用B.print_msg()

我的问题是,每次我是这样做的,它是构造A的新对象,还是最初创建的对象,我每次都得到它的引用?

换句话说,下面的代码会构造A 100次吗?

b = B()
for i in range(100):
    b.print_msg()

我开始怀疑它的原因是,在创建子对象时,不会自动调用父.__init__()方法。

2 个答案:

答案 0 :(得分:2)

super不是函数;它实际上是一个,其实例封装了有关所涉及类的方法解析顺序的知识。

super(B, self)返回一个实例(一个代理对象),它知道任何类型self具有的MRO,以及您希望在{{1}之间跳过MRO中的类的事实}和self.__class__。当您在代理上调用方法时,它会找到要调用的正确方法,然后将B作为参数传递给该方法。

假设对象self是一个类self的实例,其MRO看起来像A。通常,拨打[A, C1, C2, C3, C4, B, C5, C6]会检查A.foo()是否有方法A,如果没有,请继续按顺序检查fooC1等直到它找到一个方法C2的类。 foo返回的代理基本上是“使用super(B, self)的MRO”,这样当您编写[B, C5, C6]时,如果super(B, self).foo()没有,Python会直接跳至B不存在。

在绝大多数情况下,A.foo用于跳过实例的类本身,从MRO的前面修剪一个类。通过让您省略super的参数,这是Python 3简化的行为。

答案 1 :(得分:1)

不,下面的代码将构造一个A恰好一次:

b = B()
for i in range(100):
    b.print_msg()

这将隐含在行b = B()中,因为B是A.

对象super(B, self)代理。它将使用类对象A,但不需要实际创建A实例