Was ist eine gute und saubere ereignisgesteuerte Programmierung in Python? Ich erlebe derzeit das, was als „Rückruf-Hölle“ bezeichnet wird. und möchten wissen, wie man es richtig macht.


Beste Antwort

Basierend auf den obigen Kommentaren ist hier eine allgemeine Strategie. Offensichtlich sind die Details natürlich sehr wichtig .

Grundsätzlich haben Sie zwei Teile.

Das Ereignisereignis oder der Herausgeber „ ist dafür verantwortlich Pflege einer Liste aller Funktionen, die aufgerufen werden sollen, wenn ein Ereignis eintritt. Es verfügt über eine fire() -Methode, die diese Liste durchläuft und nacheinander alle Funktionen aufruft. Es sollte wahrscheinlich auch Methoden zum Verwalten der Liste enthalten (Entfernen einer Funktion aus der Liste, die nicht mehr benötigt wird).

Die -Handler oder „ Abonnenten“ sind Funktionen, die Sie aufrufen werden, wenn das Ereignis tatsächlich eintritt. Das einzig schwierige daran ist, dass Sie die Signatur der Handler steuern müssen, damit das Ereignis sie aufrufen kann, ohne zusätzliche Selbstbeobachtung durchzuführen.

Hier ist ein äußerst minimales Beispiel:

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")

Das sollte

example handler fired ("started",)

example handler fired ("stopped", "optional extra arg")

Die Hauptverwaltungsprobleme sind:

Ausnahmebehandlung. Sie müssen entscheiden, ob der Handler ausnahmesicher sein muss oder nicht. Wenn dies nicht der Fall ist, ist der obige Code mehr oder weniger in Ordnung. Wenn Sie jedoch nicht möchten, dass ein schlechter Abonnent das gesamte Programm herunterfährt, müssen Sie entscheiden, wie mit einer Ausnahme umgegangen werden soll und ob der betreffende Handler abgemeldet werden soll oder nicht

Speicherverwaltung. In diesem Beispiel wird nur eine Funktion als Handler verwendet, es sei denn, Sie del () die Funktion, die Sie nicht benötigen Verwalten Sie die Lebensdauer. Sie möchten jedoch häufig entweder aufrufbare Objekte oder Elementfunktionen als Handler / Abonnenten haben. In diesem Fall müssen Sie wahrscheinlich schwache Referenzen anstelle der im Beispiel verwendeten naiven Menge verwenden. Andernfalls halten die Ereignishandler Objekte am Leben, nachdem sie aus dem Gültigkeitsbereich herausgefallen sein sollten und Müll gesammelt werden sollten.

Metadaten: Das Beispiel enthält ein wenig Metadaten – die Zeichenfolge, die als Event() s werden deklariert. Ihre Anwendung benötigt möglicherweise mehr oder weniger. Mehr Metadaten bedeuten normalerweise mehr Kopplung, was nicht ideal ist. Wenn Ihre Handler jedoch alle die Signatur (*args, **kwargs) haben, können Sie die Daten jederzeit übergeben und dann auf Handlerebene entscheiden, ob Sie sich dafür interessieren oder nicht.

Gute Referenz : Das Beobachtermuster in Python

Beispiel für die Grundidee in Aktion: theodox / mGui

Antwort

Wenn Sie zur Website des Tornado-Webframeworks gehen, wird eine Beispielseite angezeigt. Auf dieser Seite befindet sich ein Beispiel für einen Chat-Anwendungscode. Es ist unglaublich kurz und verständlich.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.