三重继承会导致元类冲突...有时 [英] Triple inheritance causes metaclass conflict... Sometimes
问题描述
看起来,即使我不想做任何事情,我也偶然发现了一个元类地狱.
Looks like I stumbled upon a metaclass hell even when I didn't wanted anything to do with it.
我正在使用PySide在Qt4中编写一个应用程序.我想将事件驱动的部分与UI定义分开,后者是从Qt Designer文件生成的.因此,我创建了一个"controller"类,但是为了简化我的生活,我还是对它们进行了多重继承.一个例子:
I'm writing an app in Qt4 using PySide. I want to separate event-driven part from UI definition, which is generated from Qt Designer files. Hence I create a "controller" classes, but to ease my life I multiple-inherit them anyways. An example:
class BaseController(QObject):
def setupEvents(self, parent):
self.window = parent
class MainController(BaseController):
pass
class MainWindow(QMainWindow, Ui_MainWindow, MainController):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.setupEvents(self)
这按预期工作.它还具有(QDialog
,Ui_Dialog
,BaseController
)的继承.但是,当我子类BaseController
并尝试从所述子类继承(代替BaseController
)时,我收到错误消息:
This works as expected. It also has inheritance from (QDialog
, Ui_Dialog
, BaseController
). But when I subclass BaseController
and try to inherit from said subclass (in place of BaseController
), I receive an error:
TypeError:调用元类基数时出错 元类冲突:派生类的元类必须是其所有基元元类的(非严格)子类
TypeError: Error when calling the metaclass bases metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
说明:QMainWindow
和QDialog
均从QObject
继承.由于Qt事件系统的特殊性,BaseController
也必须从中继承. Ui_类仅继承自简单的Python对象类.我搜索了解决方案,但所有解决方案都涉及有意使用元类的情况.所以我一定在做些非常错误的事情.
Clarification: Both QMainWindow
and QDialog
inherit from QObject
. BaseController
must also inherit from it because of Qt event system peculiarities. Ui_ classes only inherit from simple Python object class. I searched for solutions, but all of them involve cases of intentionally using metaclasses. So I must be doing something terribly wrong.
通过添加图形,我的描述可能会更清楚.
My description may be clearer by adding graphs.
工作示例:
QObject
| \___________________
| object |
QMainWindow | BaseController
| /---Ui_MainWindow |
| | MainController
MainWindow-----------------/
另一个工作示例:
QObject
| \___________________
| object |
QDialog | BaseController
| /---Ui_OtherWindow |
| | |
OtherWindow----------------/
不起作用的示例:
QObject
| \___________________
| object |
QDialog | BaseController
| /---Ui_OtherWindow |
| | OtherController
OtherWindow----------------/
推荐答案
错误消息表明您在层次结构中的某个位置有两个冲突的元类.您需要检查每个类和QT类,以找出冲突的位置.
The error message indicates that you have two conflicting metaclasses somewhere in your hierarchy. You need to examine each of your classes and the QT classes to figure out where the conflict is.
以下是设置相同情况的一些简单示例代码:
Here's some simple example code that sets up the same situation:
class MetaA(type):
pass
class MetaB(type):
pass
class A:
__metaclass__ = MetaA
class B:
__metaclass__ = MetaB
我们不能直接对这两个类进行子类化,因为python不知道要使用哪个元类:
We can't subclass both of those classes directly, because python wouldn't know which metaclass to use:
>>> class Broken(A, B): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict)
subclass of the metaclasses of all its bases
该错误试图告诉我们的是,我们需要通过引入第三个元类来解决这两个元类之间的冲突,这是基类中所有元类的子类.
What the error is trying to tell us is that we need to resolve the conflict between the two metaclasses by introducing a third metaclass that is a subclass of all the metaclasses from the base classes.
我不确定是否比错误消息本身更清晰,但是基本上,您可以通过执行以下操作来修复它:
I'm not sure that's any clearer than the error message itself, but basically, you fix it by doing this:
class MetaAB(MetaA, MetaB):
pass
class Fixed(A, B):
__metaclass__ = MetaAB
此代码现在可以编译并正确运行.当然,在实际情况下,您的解决冲突的元类将不得不决定采用哪种父元类行为,您必须根据应用程序的要求自行确定哪些行为.
This code now compiles and runs correctly. Of course, in the real situation, your conflict-resolving metaclass would have to decide which of the parent metaclass behaviors to adopt, which you'll have to figure out for yourself from your application's requirements.
请记住,您的继承类仅获得两个元类中的一个.__init__
方法有时可以完成所有工作,因此在很多情况下,您将不得不添加__init__
并以某种方式帮助他们相处.
Bear in mind that your inherited class only gets one of the two metaclass.__init__
methods, which sometimes do all the work, so in a lot of cases, you are going to have to add an __init__
that calls into both in some way that helps them get along.
这篇关于三重继承会导致元类冲突...有时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!