Chain-calling parent constructors in python
考虑一下这一点-从A继承的基类A、从B继承的类B、从B继承的类C。在构造函数中调用父类构造函数的一般方法是什么?如果这听起来仍然太模糊,这里有一些代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class A(object):
def __init__(self):
print"Constructor A was called"
class B(A):
def __init__(self):
super(B,self).__init__()
print"Constructor B was called"
class C(B):
def __init__(self):
super(C,self).__init__()
print"Constructor C was called"
c = C() |
我现在就是这样做的。但它看起来仍然有点非泛型——您仍然必须手工传递正确的类型。
现在,我已经尝试使用self.__class__作为super()的第一个参数,但是,显然它不起作用-如果您将它放入构造函数c中足够公平,B的构造函数就会被调用。如果在B中做同样的操作,"self"仍然指向C的一个实例,因此您最终再次调用B的构造函数(这以无限递归结束)。
现在不需要考虑钻石继承,我只是想解决这个具体的问题。
- "但它似乎仍然有点太非常规-您仍然必须手动传递正确的类型。"??您正在将类名传递给super()。你永远不需要知道超类或其他什么。这是如何非通用的?它会造成什么问题?你能举出一个例子来说明它在哪里中断吗?
- 我还没准备好回答这个问题。但是无论如何,如果类被重命名怎么办?如果我想编写一个decorator函数来自动化这种链接,该怎么办?现在我明白了,这是不可能的,但在问这个问题的时候,我不知道。
- @害羞地说,如果我理解你的问题,你描述什么是可能的。如果理解MRO,可以使用super()使父引用完全通用。谷歌"python super is super",观看视频。
- @实际上,再次阅读你的问题,我相信你正在经历的无限递归不是你想象的那样。我相信MRO订单让你打电话给一个你不打算打的建造商。不久前我自己也处理过同样的事情。无论您将什么传递给super的第一个参数,super都将调用mro中的第一个构造函数,而不是您传入的类型。例如,如果在C的构造函数中调用super(self.u classuuuuuu,self),那么仍然会调用B的构造函数,因为它是MRO中的第一个父级。
python 3包括一个改进的super(),它允许如下使用:
- 如果我有多个父类,超级如何标识要调用的父类?
- @kracekumar它将由类的方法解析顺序(mro)决定,您可以通过调用MyClassName.mro()来找到它。我可能是不正确的,但我相信第一个指定的父母是将调用__init__的父母。
- @讽刺的是,你介意详细阐述一下这个改进的超级帮助是如何解决这个问题的吗?我刚找到这条旧线,我也有同样的问题。自从第一次问到这个问题以来,python 2.x的功能有没有改进?
- @用户815423426因为它使up调用更加通用,不再重复类名,这是原始问题的主题。
- @kracekumar,super(x,obj)实际上返回一个特殊的"super"对象,当您对它进行属性访问时,它将返回如果类x没有任何属性的话将被返回的属性。例如,super(x,obj)。init将返回obj的init方法,就好像x类中的init不存在一样。现在,如果类x有两个父类,而x."init"不存在,则默认行为是只调用其中一个父类的init,而不是同时调用这两个父类。这就是Super正在做的……给你一个父母。
您这样做确实是推荐的方法(对于python 2.x)。
类是否显式传递给super是一个样式问题,而不是功能问题。将类传递给super符合Python的"显式优于隐式"哲学。
- 我很难决定接受哪个答案,但我会接受这个答案,因为它与我使用的Python版本相关。
- 在python 2.6中,我使用这个方法得到了TypeError: super() argument 1 must be type, not classobj。我错过什么了吗?
- @leopd:super()只适用于新类型的类,即必须从object继承。
- 你究竟怎么能说Python的哲学是"明而不隐"。它不是强类型语言。
- @Philluminati:见python.org/dev/peps/pep-0020
- Python是一种强类型语言,但它是动态类型的。弱类型和动态类型之间有区别。
- 在python 2.7中,您得到:typeerror:必须是类型,而不是classobj
- @乔希斯密顿:我绝对不会将python归类为强类型。我想定义是不一样的,但对我来说,强类型语言是所有变量和参数都必须有一个类型的语言。在Python中,情况并非如此。我可以对变量调用方法,而不知道它是什么对象或它是什么类型的。只要该类型具有具有正确输入参数的方法,就可以调用它。我不是要开始讨论强类型的定义。我只是想在这个列表中显示一个相反的观点,以表明你不一定是对的。:)
- @不过,科学男孩的定义很清楚。python是强动态的。类似Java的东西是强静态的。PHP是弱动态的。静态类型保证(至少在某些限制内)输入参数是正确的类型。强类型化意味着编译器/运行时不会试图将一种类型的值强制为另一种类型。比如把"1"改成"1",这样你就可以对它进行数学运算了。请看这里:wiki.python.org/moin/…
- 这个答案对于显式来说确实没有意义,而且您可能会发现将类传递给super(cls,instance)调用并不能满足您的需要。它实际上是隐式调用基于方法解析顺序的父类。你可以在这里搜索更多信息。要按照您的建议显式调用类构造函数,应该使用@jay parikh的答案。使用super()主要是隐式引用,以便将类与其父类分离。
你可以简单地写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class A(object):
def __init__(self):
print"Constructor A was called"
class B(A):
def __init__(self):
A.__init__(self)
# A.__init__(self,<parameters>) if you want to call with parameters
print"Constructor B was called"
class C(B):
def __init__(self):
# A.__init__(self) # if you want to call most super class...
B.__init__(self)
print"Constructor C was called" |