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

Chr*_*ger 15 python constructor method-resolution-order python-3.x

当从内置类型以及其他类派生时,似乎内置类型的构造函数不会调用超类构造函数.这导致__init__方法不会被调用MRO中内置之后的类型.

例:

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()
Run Code Online (Sandbox Code Playgroud)

在此示例中,永远不会调用A .__ init__.当B被定义为class B(A, list)相反 - 切换继承顺序 - 它按预期工作(即调用A .__ init__).

对继承顺序的这种非常微妙的依赖似乎是非pythonic的,它是这样的吗?这也意味着你必须永远不要从复杂类层次结构中的内置类型派生,因为当别人从你的类派生时(维护恐怖),你无法知道内置函数在MRO中的最终位置.我错过了什么吗?

额外信息:Python 3.1版

Sve*_*ach 10

正确使用super()是相当微妙的,如果协作方法并非都具有相同的签名,则需要小心.__init__()方法的通常模式如下:

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)
Run Code Online (Sandbox Code Playgroud)

请注意,这要求所有方法协作,并且所有方法都需要一个稍微兼容的签名,以确保调用该方法的位置无关紧要.

内置类型的构造函数没有允许参与此类协作的构造函数签名.即使他们确实调用了super().__init__()这个,但是除非所有的构造函数签名都是统一的,否则这将是无用的.所以最后你是对的 - 它们不适合参与协作构造函数调用.

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

如果你想要super()用于构造函数,你确实不应该object在多个inheirtance hierachies中使用内置类型的子类(除了).进一步阅读: