ChatGPT解决这个技术问题 Extra ChatGPT

python中的链式调用父初始化器[重复]

这个问题在这里已经有了答案:How to invoke the super constructor in Python? (7 个回答) 5 年前关闭。

考虑一下-基类A,从A继承的B类,从B继承的C类。在初始化程序中调用父类初始化程序的通用方法是什么?如果这听起来仍然太模糊,这里有一些代码。

class A(object):
    def __init__(self):
        print "Initialiser A was called"

class B(A):
    def __init__(self):
        super(B,self).__init__()
        print "Initialiser B was called"

class C(B):
    def __init__(self):
        super(C,self).__init__()
        print "Initialiser C was called"

c = C()

这就是我现在的做法。但它似乎仍然有点太不通用 - 你仍然必须手动传递正确的类型。

现在,我尝试使用 self.__class__ 作为 super() 的第一个参数,但是,显然它不起作用——如果你把它放在 C 的初始化程序中——很公平,B 的初始化程序会被调用。如果你在 B 中做同样的事情,“self”仍然指向 C 的一个实例,所以你最终会再次调用 B 的初始化程序(这以无限递归结束)。

现在不需要考虑钻石继承,我只是对解决这个特定问题感兴趣。

“但它似乎仍然有点太不通用 - 你仍然必须手动传递正确的类型。”??您将类名传递给 super()。你永远不需要知道超类或其他任何东西。这是如何非通用的?它会产生什么问题?你能举个例子吗?
如果满了,我还没准备好回答这个问题。但是无论如何,如果类被重命名怎么办?如果我想编写一个装饰器函数来自动化这种链接怎么办?现在我明白了,这是不可能的,但在提出这个问题时我并不知道。
@shylent,如果我理解你的问题,你的描述是可能的。如果您了解 mro,则可以使用 super() 使父引用完全通用。谷歌“python super is super”,观看视频。
@shylent 实际上,再次阅读您的问题,我相信您正在经历的无限递归并不是您认为的那样。我相信 mro 订单会让你调用一个你不打算调用的构造函数。不久前,我自己也处理过同样的事情。不管你传给 super 的第一个参数是什么,super 都会调用 mro 中的第一个构造函数,而不是你传入的类型。例如,如果你在 C 的构造函数中调用 super(self.__class__, self),你会仍然调用 B 的构造函数,因为它是 mro 中的第一个父级。

i
ironfroggy

Python 3 包含一个改进的 super() ,它允许像这样使用:

super().__init__(args)

如果我有多个父类,如何超级识别要调用的父类?
@kracekumar 这将由类的方法解析顺序 (MRO) 确定,您可以通过调用 MyClassName.mro() 来找到它。我可能不正确,但我相信第一个指定的父级是 __init__ 将被调用的那个。
@ironfroggy,您介意详细说明这个改进后的超级如何帮助解决这个问题吗?我刚刚找到了这个旧线程,我也有同样的问题。自从第一次提出这个问题以来,Python 2.x 的情况是否有所改进?
@user815423426 因为它使向上调用更加通用,不再重复类名,这是原始问题的主题。
@kracekumar, super(X,obj) 实际上返回一个特殊的“超级”对象,当您对其进行属性访问时,将返回如果类 X 根本没有属性时将返回的属性。例如, super(X,obj).__init__ 将返回您的 obj 的 init 方法,就好像 X 类中的 init 不存在一样。现在,如果类 X 有两个父类,并且 X.__init__ 不存在,则默认行为是只调用其中一个父类的 init,而不是两者。这实际上就是 super 正在做的事情……给你一个父母。
d
dF.

您这样做的方式确实是推荐的方式(对于 Python 2.x)。

类是否显式传递给 super 的问题是样式问题而不是功能问题。将类传递给 super 符合 Python 的“显式优于隐式”的理念。


我很难决定接受哪个答案,但我会接受这个答案,仅仅是因为它与我正在使用的 python 版本相关。
在 Python 2.6 中,我使用此方法得到 TypeError: super() argument 1 must be type, not classobj。我错过了什么吗?
@Leopd:super() 仅适用于新式类,即您必须从 object 继承。
Python 是一种强类型语言,但它是动态类型的。弱类型和动态类型之间存在差异。
@TheScienceBoy 虽然定义很明确。 Python 是强动态的。像 Java 这样的东西是强静态的。 PHP 是弱动态的。静态类型保证(至少在某些限制内)输入参数是正确的类型。强类型化意味着编译器/运行时不会尝试将一种类型的 value 强制转换为另一种类型。就像将“1”更改为 1,这样您就可以对其进行数学运算。请在此处查看:wiki.python.org/moin/…
b
bignose

你可以简单地写:

class A(object):

    def __init__(self):
        print "Initialiser A was called"

class B(A):

    def __init__(self):
        A.__init__(self)
        # A.__init__(self,<parameters>) if you want to call with parameters
        print "Initialiser B was called"

class C(B):

    def __init__(self):
        # A.__init__(self) # if you want to call most super class...
        B.__init__(self)
        print "Initialiser C was called"