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()
在本例中,您尝试将clstree和您自己的clstree对象组合在一起。因为clstree忘记在其构造函数中调用super(),所以他们的孩子在使用super()时无法执行clstree的构造函数。你知道吗
因此,输出将如下所示:
Here's Three
Here's Four
显然,我可以手动调用ClsFour的每一个基,而不是使用super(),但是当这个问题分散在我的代码库中时就有点复杂了。你知道吗
顺便说一句,黑匣子的东西是PySide:)
副刊:
多亏了@WillemVanOnsem和@RaymondHettinger,前面的问题就解决了。但经过进一步的调查,我发现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>
它不打印“这里是MyObject”,super()的init属性也有不同的类型。以前,我试图将这个问题简化为ClsFour。但现在我觉得不完全一样了。你知道吗
我猜问题发生在shiboken图书馆,但我不确定。你知道吗
提示:
这个问题也出现在PyQt上下文中,但是可以让MyObject从QObject继承来解决。这个解决方案在PySide是无用的。你知道吗
关于特定于PySide/PyQt4的问题:一种解决方案是确保任何mixin始终在基类定义中位于Qt类之前:
输出:
(注意:PyQt5已经改进了Support for Cooperative Multi-inheritance,所以这里不会出现这个问题)。你知道吗
摘要
这在Super Considered Super博客文章的“如何合并非合作类”一节中有介绍。你知道吗
关键是通过调用super()创建一个按规则运行的adapter class来协同工作。使用该适配器包装原始类。你知道吗
编制代码
在下面的代码中,
AdaptThree
是新的适配器类,ClsFour 现在继承自adaptethree而不是原来的blackbox非合作类。你知道吗这将输出:
其他详细信息
在OP的例子中,ClsTwo看起来也是不合作的,也应该进行包装。
假设这些类具有初始化以外的方法。适配器类也需要包装和分派这些调用。
根据应用程序的不同,使用组合而不是继承可能更容易。
super()
是一个代理对象,它使用方法解析顺序(MRO)来确定在对super()
执行调用时要调用的方法。你知道吗如果我们检查
ClassFour
的__mro__
,我们得到:或者我自己把它缩短了(不是Python输出):
现在
super(T,self)
是一个代理对象,它使用来自(但不包括)T
的MRO。这意味着super(ClsFour,self)
是一个代理对象,它可以处理:如果查询一个类的属性(方法也是属性),那么Python将遍历MRO并检查元素是否具有这样的属性。因此它将首先检查
ClsThree
是否有__init__
属性,如果没有,它将继续在ClsThreee
中查找它,依此类推。从它找到这样的属性的那一刻起,它将停止并返回它。你知道吗因此
super(ClsFour,self).__init__
将返回ClsThree.__init__
方法。MRO还用于查找未在类级别定义的方法、属性等。因此,如果您使用self.x
,x
不是对象的属性,也不是ClsFour
对象的属性,它将再次遍历MRO以搜索x
。你知道吗如果要调用all的
__init__
调用ClassFour
的直接父级,可以使用:这可能是最优雅的,因为如果基地改变,它仍然会工作。注意,您必须确保每个父级都存在
__init__
。但是,由于它是在object
级别定义的,因此我们可以放心地假设这一点。然而,对于其他属性,我们不能做出这样的假设。你知道吗编辑:因此
super()
并不必要地指向该阶级的父母、祖父母和/或祖先。但是对于对象的父类。你知道吗ClsThree
类中的super(ClsThree,self)
将-假设它是一个ClsFour
对象,使用相同的mro(因为它从self
获取mro
)。因此super(ClsThree,self)
将检查以下类序列:例如,如果我们写(在任何类的范围之外)
super(ClsTwo,entity).__init__()
,我们得到:相关问题 更多 >
编程相关推荐