三重继承会导致元类冲突...有时 [英] Triple inheritance causes metaclass conflict... Sometimes

查看:57
本文介绍了三重继承会导致元类冲突...有时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看起来,即使我不想做任何事情,我也偶然发现了一个元类地狱.

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)

这按预期工作.它还具有(QDialogUi_DialogBaseController)的继承.但是,当我子类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

说明:QMainWindowQDialog均从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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆