Python 3内置类型__init__不调用super().__ init__?

Python 3 builtin types __init__ doesn't call super().__init__?

当从内置类型以及其他类派生时,似乎内置类型的构造函数不调用超级类构造函数。这导致没有为MRO中内置项之后的类型调用_uu init_uuu方法。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A:
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print("A().__init__()")

class B(list, A):
    def __init__(self, *args, **kwargs):
        print("B().__init__() start")
        super().__init__(*args, **kwargs)
        print("B().__init__() end")

if __name__ == '__main__':
    b = B()

在这个示例中,从来没有调用过.u init。当b被定义为class B(A, list)而不是切换继承顺序时,它按预期工作(即,调用a。"uu init")。

这种对继承顺序的微妙依赖似乎相当不靠谱,它是这样打算的吗?它还意味着您永远不能从复杂类层次结构中的内置类型派生,因为当其他人从您的类派生时,您不知道该内置类型在MRO中的结束位置(维护恐怖)。我错过什么了吗?

额外信息:python 3.1版


正确使用super()是相当微妙的,如果协作方法不都具有相同的签名,则需要注意。__init__()方法的常见模式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A(object):
    def __init__(self, param_a, **kwargs):
        self.param_a = param_a
        super(A, self).__init__(**kwargs)

class B(A):
    def __init__(self, param_b, **kwargs):
        self.param_b = param_b
        super(B, self).__init__(**kwargs)

class C(A):
    def __init__(self, param_c, **kwargs):
        self.param_c = param_c
        super(C, self).__init__(**kwargs)

class D(B, C):
    def __init__(self, param_d, **kwargs):
        self.param_d = param_d
        super(D, self).__init__(**kwargs)

d = D(param_a=1, param_b=2, param_c=3, param_d=4)

请注意,这需要所有方法协作,并且所有方法都需要某种兼容的签名,以确保在哪一点调用该方法并不重要。

内置类型的构造函数没有允许参与这种协作的构造函数签名。即使他们调用了super().__init__(),除非所有的构造函数签名都是统一的,否则这将是非常无用的。所以最终你是对的——它们不适合在协作的构造函数调用中参与。

只有当所有协作方法具有相同的签名(如__setattr__())或使用上述(或类似)模式时,才能使用super()。不过,使用super()并不是调用基类方法的唯一模式。如果多重继承模式中没有"菱形",则可以使用显式的基类调用,例如B.__init__(self, param_a)。具有多个基类的类只调用多个构造函数。A即使有钻石,有时也可以使用明确的电话,只要你注意到一个__init__()可能会被多次呼叫而不会造成伤害。

如果您无论如何都想将super()用于构造,那么您确实不应该在多个固有层次中使用内置类型的子类(object除外)。进一步阅读:

  • Raymond Hettinger的python的super()被认为是super!
  • 詹姆斯·奈特的Python超级棒极了,但你不能用它
  • 小精灵