Najlepsza odpowiedź
Na podstawie powyższych komentarzy, oto ogólna strategia. Oczywiście szczegóły mają duże znaczenie .
Zasadniczo będziesz miał dwie części.
obiekt zdarzenia lub „ wydawca” jest odpowiedzialny za prowadzenie listy wszystkich funkcji, które powinny być wywoływane w przypadku wystąpienia zdarzenia. Posiada metodę fire()
, która zapętla tę listę i wywołuje po kolei wszystkie funkcje. Prawdopodobnie powinien mieć również metody zarządzania listą (usuwanie funkcji z listy nie jest potrzebna).
moduły obsługi lub „ subskrybenci” to funkcje, które „zamierzasz wywołać, gdy zdarzenie faktycznie nastąpi. Jedynym trudnym problemem jest to, że musisz kontrolować podpis modułów obsługi, aby zdarzenie mogło je wywołać bez wykonywania dodatkowej introspekcji.
Oto ultra minimalny przykład:
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")
To powinno dać
example handler fired ("started",)
example handler fired ("stopped", "optional extra arg")
Główne kwestie związane z zarządzaniem to:
Obsługa wyjątków. musisz zdecydować, czy program obsługi ma być bezpieczny dla wyjątków, czy nie. Jeśli nie, powyższy kod jest mniej więcej w porządku, ale jeśli nie chcesz, aby zły subskrybent spowodował wyłączenie całego programu, musisz zdecydować, jak sobie poradzić z wyjątkiem i czy „anulować subskrypcję” programu obsługującego. .
Zarządzanie pamięcią. W przykładzie użyto tylko funkcji jako modułu obsługi; chyba że usuniesz () funkcję, której nie musisz zarządzaj jego okresem życia. Jednak często będziesz chciał mieć wywoływalne obiekty lub funkcje składowe jako programy obsługi / subskrybenci. Jeśli tak, prawdopodobnie będziesz musiał użyć słabych referencji zamiast naiwnego zestawu użytego w przykładzie – w przeciwnym razie programy obsługi zdarzeń będą utrzymywać obiekty przy życiu po tym, jak powinny wypadły poza zakres i powinny zostać wyrzucone.
Metadane: Przykład zawiera trochę metadanych – ciąg, który jest przekazywany jako Event()
s są deklarowane. Twoja aplikacja może potrzebować więcej lub mniej niż to. Więcej metadanych oznacza zwykle większe sprzężenie, co nie jest idealne. Jeśli jednak wszystkie twoje programy obsługi mają podpis (*args, **kwargs)
, zawsze możesz przekazać dane, a następnie zdecydować na poziomie obsługi, czy ci na tym zależy, czy nie.
Dobre odniesienie : Wzorzec obserwatora w Pythonie
Przykład podstawowej idei w działaniu: theodox / mGui
Odpowiedź
Jeśli wejdziesz na stronę internetową frameworka tornado, znajdziesz tam przykładową stronę. Na tej stronie znajduje się przykładowy kod aplikacji do czatu. Jest niefortunnie krótki i zrozumiały.