class ClsOne(object):
def __init__(self):
super(ClsOne, self).__init__()
print "Here's One"
class ClsTwo(ClsOne):
def __init__(self):
super(ClsTwo, self).__init__()
print "Here's Two"
class ClsThree(ClsTwo): # Refer to one blackbox object
def __init__(self):
# super(ClsThree, self).__init__()
print "Here's Three"
class ClsThreee(ClsTwo): # Refer to your custom object
def __init__(self):
super(ClsThreee, self).__init__()
print "Here's Threee"
class ClsFour(ClsThree, ClsThreee): # Multiple Inheritance
def __init__(self):
super(ClsFour, self).__init__()
print "Here's Four"
entity = ClsFour()
在这种情况下,您尝试将 ClsThree (来自单个编译库并且很难更改)和您自己的 ClsThreee 对象组合在一起。因为 ClsThree 忘记在其构造函数中调用 super(),所以当他们使用 super()时,他们的孩子无法执行ClsThreee的构造函数。
结果,输出就像这样:
Here's Three
Here's Four
显然,我可以手动调用ClsFour的每个基础而不是使用super(),但是当这个问题散布在我的代码库中时,它有点复杂。
顺便说一句,那个黑盒子的东西是PySide:)
补充:
感谢@WillemVanOnsem和@RaymondHettinger,之前的ClsFour问题已经解决了。但通过一些进一步的调查,我发现PySide中的类似问题并没有相同的概念。
在ClsFour上下文中,如果您尝试运行:
print super(ClsFour, self).__init__
你会得到:
<bound method ClsFour.__init__ of <__main__.ClsFour object at 0x00000000031EC160>>
但是在下面的PySide上下文中:
import sys
from PySide import QtGui
class MyObject(object):
def __init__(self):
super(MyObject, self).__init__()
print "Here's MyObject"
class MyWidget(QtGui.QWidget, MyObject):
def __init__(self):
super(MyWidget, self).__init__()
app = QtGui.QApplication(sys.argv)
widget = MyWidget()
print super(MyWidget, widget).__init__
结果是:
<method-wrapper '__init__' of MyWidget object at 0x0000000005191D88>
它没有打印&#34;这里的MyObject&#34;而且super()的init属性也有不同的类型。以前,我尝试将此问题简化为ClsFour。但现在我认为它并不完全相同。
我猜这个问题发生在shiboken库中,但我不确定。
TIPS:
问题也出现在PyQt上下文中,但是你可以让MyObject继承自QObject来解决。这个解决方案在PySide中没用。
答案 0 :(得分:3)
super()
是代理对象,它使用 方法解析订单(MRO) 来确定您在调用时调用的方法在super()
上进行通话。
如果我们检查__mro__
的{{1}},我们会得到:
ClassFour
或者让自己缩短(不是Python输出):
>>> ClsFour.__mro__
(<class '__main__.ClsFour'>, <class '__main__.ClsThree'>, <class '__main__.ClsThreee'>, <class '__main__.ClsTwo'>, <class '__main__.ClsOne'>, <type 'object'>)
现在>>> ClsFour.__mro__
(ClsFour, ClsThree, ClsThreee, ClsTwo, ClsOne, object)
是一个代理对象,它使用(但不包括)super(T,self)
的MRO。这意味着T
是一个可以使用的代理对象:
super(ClsFour,self)
如果查询类的属性(方法也是属性)会发生什么,Python将遍历MRO并检查元素是否具有此属性。因此,它将首先检查(ClsThree, ClsThreee, ClsTwo, ClsOne, object) # super(ClsFour,self)
是否具有ClsThree
属性,否则它将继续在__init__
中查找,依此类推。从找到这样的属性的那一刻起,它就会停止并返回它。
因此ClsThreee
将返回super(ClsFour,self).__init__
方法。 MRO还用于查找未在类级别定义的方法,属性等。因此,如果您使用ClsThree.__init__
而self.x
不是对象的属性,也不是x
对象的属性,它将再次遍历MRO以搜索ClsFour
。
如果您想拨打所有的x
直接 __init__
的父母,您可以使用:
ClassFour
这可能是最优雅的,因为如果基地改变,它仍然会起作用。请注意,您必须确保每个父级都存在class ClsFour(ClsThree, ClsThreee):
def __init__(self):
# call *all* *direct* parents __init__
for par in ClsFour.__bases__:
par.__init__(self)
。因为它定义在__init__
级别,我们可以安全地假设这一点。但是,对于其他属性,我们无法做出这样的假设。
编辑:请注意,因此object
不必须指向该班级的父母,祖父母和/或祖先。但是对于对象的父类。
super()
类中的super(ClsThree,self)
,如果是ClsThree
对象,则使用相同的mro (因为它需要ClsFour
来自mro
)的1}}。因此self
将检查以下类序列:
super(ClsThree,self)
例如,如果我们写(超出任何类的范围)(ClsThreee, ClsTwo, ClsOne, object)
,我们得到:
super(ClsTwo,entity).__init__()
答案 1 :(得分:0)
因为ClsThree忘记在其构造函数中调用super(),所以当他们使用super()时,他们的孩子不能执行ClsThreee的构造函数。
&#34;如何合并非合作班级&#34; Super Considered Super博文的一部分。
关键是要创建一个adapter class,通过调用 super()来遵守规则以协同行动。使用该适配器包装原始类。
在下面的代码中,AdaptThree
是新的适配器类, ClsFour
现在继承自 AdaptThree 而不是原始的blackbox非合作类。
class ClsOne(object):
def __init__(self):
print "Here's One"
class ClsTwo(ClsOne):
def __init__(self):
print "Here's Two"
class ClsThree(ClsTwo): # Refer to one blackbox object
def __init__(self):
# super(ClsThree, self).__init__()
print "Here's Three"
class AdaptThree(object):
def __init__(self):
_three = ClsThree()
super(AdaptThree, self).__init__()
class ClsThreee(ClsTwo): # Refer to your custom object
def __init__(self):
super(ClsThreee, self).__init__()
print "Here's Threee"
class ClsFour(AdaptThree, ClsThreee): # Multiple Inheritance
def __init__(self):
super(ClsFour, self).__init__()
print "Here's Four"
entity = ClsFour()
输出:
Here's Three
Here's Two
Here's Threee
Here's Four
在OP的例子中, ClsTwo 看起来也是非合作的,也应该包装好。
据推测,这些类具有初始化以外的方法。适配器类也需要包装和分派这些调用。
根据应用程序的不同,使用构图而不是继承可能更容易。
答案 2 :(得分:0)
关于PySide / PyQt4特有的问题:一个解决方案是确保任何mixins总是在基类定义中的Qt类之前:
import sys
from PySide import QtGui
class MyObject(object):
def __init__(self, parent=None, other=None):
super(MyObject, self).__init__(parent)
print "Here's MyObject: %r" % other
class MyWidget(MyObject, QtGui.QWidget):
def __init__(self, parent=None, other=None):
super(MyWidget, self).__init__(parent, other)
app = QtGui.QApplication(sys.argv)
parent = QtGui.QWidget()
widget = MyWidget(parent, 'FOO')
print super(MyWidget, widget).__init__
# check that the QWidget.__init__ was called correctly
print 'widget.parent() is parent:', widget.parent() is parent
输出:
Here's MyObject: 'FOO'
<bound method MyWidget.__init__ of <__main__.MyWidget object at 0x7f53b92cca28>>
widget.parent() is parent: True
(注意:PyQt5已经改进了Support for Cooperative Multi-inheritance,所以这个问题并没有出现。)