Co to jest dobre i czyste programowanie sterowane zdarzeniami w Pythonie? Obecnie doświadczam czegoś, co nazywa się ' Piekło oddzwonienia ' i chcesz wiedzieć, jak to zrobić dobrze.


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.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *