在一个类中使用HasTraits和PyQt信号

Hei*_*urt 6 python signals pyqt traits

我有一个巨大的特征应用程序,它遇到了enthought特性的限制.使用@on_traits_changed装饰器时主要是性能问题.使用PyQt4(或PyQt5)信号来解决这些问题是非常简单的,如果可以的话:

from traits.api import *
from PyQt4 import QtCore

class Foo(HasTraits, QtCore.QObject):
    pass
Run Code Online (Sandbox Code Playgroud)

错误堆栈:

TypeError                                 Traceback (most recent call last)
<ipython-input-3-ecdfa57492f7> in <module>()
      2 from PyQt4 import QtCore
      3
----> 4 class Foo(HasTraits, QtCore.QObject):
      5     pass

C:\Python27\lib\site-packages\traits\has_traits.pyc in __new__(cls, class_name,
bases, class_dict)
    427
    428         # Finish building the class using the updated class dictionary:
--> 429         klass = type.__new__( cls, class_name, bases, class_dict )
    430
    431         # Fix up all self referential traits to refer to this class:

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
Run Code Online (Sandbox Code Playgroud)

但据我所知,这是不可能的.有一些解决方法吗?

编辑:增加进口

EDIT2:添加了错误堆栈

Pau*_*ius 1

我建议的解决方案是忘记 Qt。您可以使用自定义 Qt 信号和插槽执行的任何操作都可以使用纯 Python 执行。下面是一个类 PSignal 的示例,它具有与 Qt 中的 Signal 完全相同的公共接口。PSignal 的实例可以添加到任何 Python 对象中,而无需子类化 QObject,甚至根本不需要使用 Qt 库。与 Qt Signals 不同,它们可以在任何类的方法内实例化为实例变量__init__,而不是在类级别(如 Qt 要求)。此外,emit它是一个标准的 Python 方法,可以接受任意数量的参数和关键字,从而使整个机制更加“Pythonic”。这里唯一缺少的是信号和槽的线程切换行为,这似乎不是这里的要求。

通过重写方法emit_emit在子类中,您可以使这个简单的小工具适应各种情况,这是使用 Qt Signals 无法轻松做到的。

DEBUG = False

class PSignal:
    def __init__(self):
        self.__handlers = [] 

    def connect(self,f):
        """f is a python function."""
        if not callable(f):
            raise ValueError("Object {!r} is not callable".format(f))
        self.__handlers.append(f)
        if DEBUG:
            print("Connecting",f,self.__handlers)

    def disconnect(self,f):
        for f1 in self.__handlers:
            if f == f1:
                self.__handlers.remove(f)
                return

    def emit(self,*x,**y):
        self._emit(*x,**y)

    def _emit(self,*x,**y):
        for f in self.__handlers:
            try:
                if DEBUG:
                    print("emit",f,len(x),x,y)
                f(*x,**y)
            except Exception:
                print("Error in signal",f)
                traceback.print_exc()
Run Code Online (Sandbox Code Playgroud)