python中的链式调用父初始化器[重复]
Posted
技术标签:
【中文标题】python中的链式调用父初始化器[重复]【英文标题】:Chain-calling parent initialisers in python [duplicate] 【发布时间】:2010-10-28 14:09:51 【问题描述】:考虑一下 - 基类 A,类 B 继承自 A,类 C 继承自 B。在初始化程序中调用父类初始化程序的通用方法是什么?如果这听起来仍然太模糊,这里有一些代码。
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 中的第一个父级。 【参考方案1】:你可以简单地写:
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"
【讨论】:
【参考方案2】: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 正在做的事情……给你一个父母。【参考方案3】:
您这样做的方式确实是推荐的方式(对于 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 是弱动态的。静态类型保证(至少在某些限制内)输入参数是正确的类型。强类型意味着编译器/运行时不会尝试将一种类型的 值 强制转换为另一种类型。就像将“1”更改为 1,这样您就可以对其进行数学运算。请看这里:wiki.python.org/moin/…以上是关于python中的链式调用父初始化器[重复]的主要内容,如果未能解决你的问题,请参考以下文章