gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 17:07:42 28 4
gpt4 key购买 nike

从内置类型和其他类派生时,内置类型的构造函数似乎没有调用父类(super class)构造函数。这会导致 __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()

在此示例中,从未调用 A.__init__。当 B 被定义为 class B(A, list) 时——切换继承顺序——它按预期工作(即调用 A.__init__)。

这种对继承顺序的非常微妙的依赖似乎很不符合 pythonic,它是这样设计的吗?这也意味着您绝不能从复杂类层次结构中的内置类型派生,因为当其他人从您的类派生时,您无法知道内置类型最终在 MRO 中的何处(维护恐怖)。我错过了什么吗?

额外信息:Python 3.1 版

最佳答案

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)

请注意,这需要所有方法协作,并且所有方法都需要某种程度上兼容的签名,以确保调用方法的时间点无关紧要。

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

super() 只能在所有协作方法都具有相同的签名(例如 __setattr__())或者如果您使用上面的方法(或类似的方法)时使用) 图案。不过,使用 super() 并不是调用基类方法的唯一模式。如果您的多重继承模式中没有“菱形”,您可以使用显式基类调用,例如 B.__init__(self, param_a)。具有多个基类的类只需调用多个构造函数。即使有钻石,您有时也可以使用显式调用,只要您注意可以多次调用 __init__() 而不会造成伤害。

如果你想对构造函数使用 super(),你确实不应该在多个继承层次结构中使用内置类型的子类(object 除外) .进一步阅读:

关于Python 3 内置类型 __init__ 不调用 super().__init__?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8914868/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com