2015-08-07 12 views
6

Ho una grande applicazione di tratti, che si scontra con i limiti dei tratti enthought. Principalmente problemi di prestazioni quando si utilizza il decoratore @on_traits_changed. Sarebbe piuttosto semplice per aggirare questi problemi con PyQt4 (o PyQt5) segnali, se potessi fare: pilaUso di segnali HasTraits e PyQt in una classe

from traits.api import * 
from PyQt4 import QtCore 

class Foo(HasTraits, QtCore.QObject): 
    pass 

Errore:

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 

Ma da tutto quello che so che non è possibile. C'è qualche soluzione?

EDIT: aggiunto importazioni

EDIT2: aggiunto errore di stack

+0

Perché pensi che non sia possibile? Che test hai fatto? – ekhumoro

+0

Ho testato il codice che ho postato e genera un errore. Non ho trovato alcuna soluzione a questo problema, quindi ti sto chiedendo ora. – HeinzKurt

+1

@HeinzKurt. Perché è necessario utilizzare l'ereditarietà multipla? Perché non create semplicemente un'istanza interna di 'QObject' e delegate a questo? Inoltre, hai provato a utilizzare l'ultima versione di PyQt5? – ekhumoro

risposta

1

La mia soluzione suggerita è di dimenticare Qt. Tutto ciò che puoi fare con i segnali e le scanalature Qt personalizzati che puoi fare con Python puro. Ecco un esempio di una classe, PSignal, che ha esattamente la stessa interfaccia pubblica di Signal in Qt. Le istanze di PSignal possono essere aggiunte a qualsiasi oggetto Python senza la necessità di sottoclasse QObject, o anche senza usare la libreria Qt. A differenza dei segnali Qt, possono essere istanziati come variabili di istanza all'interno del metodo __init__ di qualsiasi classe, piuttosto che a livello di classe (come richiede Qt). Inoltre, emit è un metodo Python standard e accetta un numero qualsiasi di argomenti e parole chiave, rendendo così l'intero meccanismo più "Pythonic". L'unica cosa che manca qui è il comportamento di cambio di thread di segnali e slot, che non sembra essere un requisito qui.

Con i metodi di sovrascrittura emit e _emit in sottoclassi è possibile adattare questo semplice gadget a una varietà di situazioni, cosa che non è possibile fare facilmente con i segnali Qt.

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

Un bel pezzo di codice! Purtroppo condividere un'istanza di PSignal tra tutte le istanze della mia applicazione nel mio caso speciale aggiunge troppa complessità. – HeinzKurt

+1

Grazie, ma l'intenzione di PSignal non è quella di "condividere" tra altri oggetti, ma di usarlo esattamente come un segnale Qt: si collegano i client ad esso chiamando connect(), esattamente come un segnale. Ha la stessa API di Signal ed è praticamente una sostituzione drop-in, quindi non riesco a vedere come qualsiasi applicazione che utilizza i Segnali non può utilizzare PSignals, che in fin dei conti sono più leggeri. Puoi combinare liberamente PSignals e Segnali, migrando da uno all'altro come desiderato.L'ho usato per mesi e ho sostituito Signal con PSignal in molti posti, e non ho mai avuto problemi. –

+0

Grazie per il chiarimento. Anche se la tua risposta in senso stretto non risponde alla mia domanda, è comunque una soluzione molto carina, quindi l'ho accettata comunque. – HeinzKurt