2015-08-07 3 views
6

Ich habe eine große Traits-Anwendung, die in die Grenzen der enthought Merkmale läuft. Hauptsächlich Leistungsprobleme bei Verwendung des @ on_traits_changed Dekorators. Es wäre ziemlich einfach, diese Fragen mit PyQt4 (oder PyQt5) Signalen zu umgehen, wenn ich tun könnte:Verwenden Sie HasTraits und PyQt-Signale in einer Klasse

from traits.api import * 
from PyQt4 import QtCore 

class Foo(HasTraits, QtCore.QObject): 
    pass 

Fehler-Stack:

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 

Aber aus allem, was ich weiß, das ist nicht möglich. Gibt es eine Umgehungsmöglichkeit?

EDIT: hinzugefügt Importe

EDIT2: hinzugefügt Fehler-Stack

+0

Warum denkst du, dass es nicht möglich ist? Was hast du getestet? – ekhumoro

+0

Ich habe den von mir geposteten Code getestet und es wird ein Fehler ausgegeben. Ich habe keine Lösung für dieses Problem gefunden, also frage ich jetzt hier. – HeinzKurt

+1

@HeinzKurt. Warum müssen Sie die Mehrfachvererbung verwenden? Warum erstellen Sie nicht einfach eine interne Instanz von 'QObject' und delegieren Sie dazu? Haben Sie auch die neueste Version von PyQt5 getestet? – ekhumoro

Antwort

1

Meine vorgeschlagene Lösung ist über Qt zu vergessen. Alles, was Sie mit benutzerdefinierten Qt-Signalen und Slots tun können, können Sie mit reinem Python machen. Hier ist ein Beispiel für eine Klasse, PSignal, die genau die gleiche öffentliche Schnittstelle wie Signal in Qt hat. Instanzen von PSignal können zu jedem Python-Objekt hinzugefügt werden, ohne QObject ableiten zu müssen, oder sogar ohne die Qt-Bibliothek zu verwenden. Im Gegensatz zu Qt-Signalen können sie als Instanzvariablen innerhalb der __init__-Methode einer beliebigen Klasse und nicht auf Klassenebene (wie Qt benötigt wird) instanziiert werden. Außerdem ist emit eine Standard-Python-Methode und benötigt eine beliebige Anzahl von Argumenten und Schlüsselwörtern, wodurch der gesamte Mechanismus "Pythonic" wird. Das einzige, was hier fehlt, ist das Thread-Switching-Verhalten von Signalen und Slots, das hier nicht erforderlich zu sein scheint.

Durch Überschreiben der Methoden emit und _emit in Unterklassen können Sie dieses einfache Gadget an eine Vielzahl von Situationen anpassen, was Sie mit Qt-Signalen nicht leicht machen können.

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() 
+0

Sehr ordentliches Stück Code! Leider ist die gemeinsame Nutzung einer Instanz von PSignal zwischen allen Instanzen meiner Anwendung in meinem speziellen Fall zu komplex. – HeinzKurt

+1

Danke, aber die Absicht von PSignal ist es nicht, andere Objekte zu "teilen", sondern sie genau wie ein Qt-Signal zu verwenden: Sie verbinden Clients, indem Sie connect() aufrufen, genau wie ein Signal. Es hat die gleiche API wie Signal und ist praktisch ein Ersatz für den Ersatz, so dass ich nicht sehen kann, wie jede Anwendung, die Signale verwendet, PSignale nicht verwenden kann, die doch leichter sind. Sie können PSignale und Signale beliebig mischen und aufeinander abstimmen, indem Sie von einem zum anderen migrieren.Ich benutze es seit Monaten und ersetzte Signal an vielen Stellen mit PSignal und hatte nie ein Problem. –

+0

Danke für die Klarstellung. Obwohl Ihre Antwort genau meine Frage nicht beantwortet, ist es immer noch eine sehr gute Problemumgehung, also akzeptierte ich sie trotzdem. – HeinzKurt

Verwandte Themen