Migliore risposta
Sulla base dei commenti sopra, ecco “una strategia generale. Ovviamente i dettagli contano molto, ovviamente .
Fondamentalmente avrai due parti.
L oggetto evento o “ editore” è responsabile mantenere un elenco di tutte le funzioni che dovrebbero essere chiamate quando si verifica un evento. Ha un metodo fire()
che scorre su quellelenco e chiama a turno tutte le funzioni. Probabilmente dovrebbe anche avere metodi per la gestione dellelenco (non è più necessario rimuovere una funzione dallelenco).
I gestori o “ subscribers” sono funzioni che “chiamerai quando levento si verifica effettivamente. Lunico problema è che devi controllare la firma dei gestori in modo che levento possa chiamarli senza fare alcuna introspezione extra.
Ecco un esempio estremamente minimale:
class Event(object):
def \_\_init\_\_(self, *args):
self.handlers = set()
self.args = args
def add(self, fn):
self.handlers.add(fn)
def remove(self, fn):
self.handlers.remove(fn)
def \_\_call\_\_(self, *args):
"""fire the event -- uses \_\_call\_\_ so we can just invoke the object directly..."""
runtime\_args = self.args + args
for each\_handler in self.handlers:
each\_handler(*runtime\_args)
class ExampleObject(object):
"""publish start and stop events"""
def \_\_init\_\_(self):
self.start = Event("started")
self.stop = Event("stopped")
def example\_handler(*args):
""" reacts to an event"""
print "example handler fired", args
fred = ExampleObject()
fred.start.add(example\_handler)
fred.stop.add(example\_handler)
fred.start()
fred.stop("optional extra arg")
Questo dovrebbe produrre
example handler fired ("started",)
example handler fired ("stopped", "optional extra arg")
I principali problemi di gestione sono:
Gestione delle eccezioni. devi decidere se il gestore deve essere protetto dalle eccezioni o meno. In caso contrario il codice sopra è più o meno OK, ma se non vuoi che un abbonato cattivo abbandoni lintero programma devi decidere come affrontare uneccezione e se “annullare liscrizione” al gestore offensivo .
Gestione della memoria. Lesempio usa solo una funzione come gestore; a meno che tu non cancelli () la funzione che non devi gestisci la sua vita. Tuttavia, spesso vorrai avere oggetti richiamabili o funzioni membro come gestori / sottoscrittori. In tal caso, probabilmente è necessario utilizzare riferimenti deboli piuttosto che linsieme ingenuo usato nellesempio, altrimenti i gestori di eventi finiranno per mantenere in vita gli oggetti dopo che avrebbero dovuto essere esclusi dallambito e dovrebbero essere raccolti in modo garbage.
Metadati: lesempio include un po di metadati, la stringa che viene passata come Event()
vengono dichiarati. La tua applicazione potrebbe richiedere più o meno di questo. Più metadati di solito significano più accoppiamento, il che non è lideale. Tuttavia, se i tuoi gestori hanno tutti la firma (*args, **kwargs)
puoi sempre passare i dati e poi decidere a livello di gestore se ti interessa o meno.
Buon riferimento : The Observer Pattern in Python
Esempio dellidea di base in azione: theodox / mGui
Risposta
Se vai al sito web del framework web tornado, hanno una pagina di esempi. In quella pagina cè un esempio di codice dellapplicazione di chat. È incredibilmente breve e comprensibile.