PyPI-Pakete
Ab Juni 2020 sind dies die ereignisbezogenen Pakete, die auf PyPI verfügbar sind und nach dem letzten Veröffentlichungsdatum sortiert sind.
Es gibt mehr
Das sind viele Bibliotheken zur Auswahl, die eine sehr unterschiedliche Terminologie verwenden (Ereignisse, Signale, Handler, Methodenversand, Hooks, ...).
Ich versuche, einen Überblick über die oben genannten Pakete sowie die in den Antworten hier genannten Techniken zu behalten.
Zunächst einige Begriffe ...
Beobachtermuster
Der grundlegendste Stil des Ereignissystems ist die 'Bag of Handler-Methode', die eine einfache Implementierung des Observer-Musters darstellt .
Grundsätzlich werden die Handler-Methoden (Callables) in einem Array gespeichert und jeweils aufgerufen, wenn das Ereignis 'ausgelöst' wird.
Veröffentlichen-Abonnieren
Der Nachteil von Observer-Ereignissystemen besteht darin, dass Sie die Handler nur für das tatsächliche Ereignisobjekt (oder die Handlerliste) registrieren können. Zum Zeitpunkt der Registrierung muss die Veranstaltung also bereits vorhanden sein.
Aus diesem Grund gibt es den zweiten Stil von Ereignissystemen: das
Publish-Subscribe-Muster . Hier registrieren sich die Handler nicht für ein Ereignisobjekt (oder eine Handlerliste), sondern für einen zentralen Dispatcher. Auch die Benachrichtiger sprechen nur mit dem Dispatcher. Was zu hören oder zu veröffentlichen ist, wird durch 'Signal' bestimmt, das nichts weiter als ein Name (Zeichenfolge) ist.
Vermittlermuster
Könnte auch von Interesse sein: das Mediator-Muster .
Haken
Ein 'Hook'-System wird üblicherweise im Zusammenhang mit Anwendungs-Plugins verwendet. Die Anwendung enthält feste Integrationspunkte (Hooks), und jedes Plugin kann eine Verbindung zu diesem Hook herstellen und bestimmte Aktionen ausführen.
Andere Ereignisse'
Hinweis: threading.Event ist kein 'Ereignissystem' im obigen Sinne. Es ist ein Thread-Synchronisationssystem, bei dem ein Thread wartet, bis ein anderer Thread das Ereignisobjekt "signalisiert".
Netzwerk-Messaging-Bibliotheken verwenden häufig auch den Begriff "Ereignisse". manchmal sind diese im Konzept ähnlich; manchmal nicht. Sie können natürlich Thread-, Prozess- und Computergrenzen überschreiten. Siehe zB
pyzmq , pymq ,
Twisted , Tornado , gevent , eventlet .
Schwache Referenzen
Wenn Sie in Python einen Verweis auf eine Methode oder ein Objekt halten, wird sichergestellt, dass dieser nicht vom Garbage Collector gelöscht wird. Dies kann wünschenswert sein, kann aber auch zu Speicherverlusten führen: Die verknüpften Handler werden niemals bereinigt.
Einige Ereignissysteme verwenden schwache Referenzen anstelle regulärer Referenzen, um dies zu lösen.
Einige Worte zu den verschiedenen Bibliotheken
Ereignissysteme im Beobachterstil:
- zope.event zeigt, wie das funktioniert (siehe Lennarts Antwort ). Hinweis: Dieses Beispiel unterstützt nicht einmal Handlerargumente.
- Die 'Callable List'- Implementierung von LongPoke zeigt, dass ein solches Ereignissystem durch Unterklassen sehr minimalistisch implementiert werden kann
list
.
- Felks Variation EventHook sorgt auch für die Signaturen von Anrufern und Anrufern.
- spassigs EventHook (Michael Foords Event Pattern) ist eine einfache Implementierung.
- Die Ereignisklasse "Wertvolle Lektionen" von Josip ist im Grunde dieselbe, verwendet jedoch a
set
anstelle von a list
, um die Tasche zu speichern, und implementiert Geräte, __call__
die beide sinnvolle Ergänzungen sind.
- PyNotify hat ein ähnliches Konzept und bietet zusätzliche Konzepte für Variablen und Bedingungen ('variabel geändertes Ereignis'). Die Homepage funktioniert nicht.
- axel ist im Grunde ein Bag-of-Handler mit mehr Funktionen in Bezug auf Threading, Fehlerbehandlung, ...
- Für Python-Dispatch müssen die geraden Quellklassen abgeleitet werden
pydispatch.Dispatcher
.
- buslane ist klassenbasiert, unterstützt Einzel- oder Mehrfachhandler und ermöglicht umfangreiche Typhinweise.
- Pithikos ' Observer / Event ist ein leichtes Design.
Publish-Subscribe-Bibliotheken:
- Blinker hat einige raffinierte Funktionen wie automatische Trennung und Filterung basierend auf dem Absender.
- PyPubSub ist ein stabiles Paket und verspricht "erweiterte Funktionen, die das Debuggen und Verwalten von Themen und Nachrichten erleichtern".
- pymitter ist ein Python-Port von Node.js EventEmitter2 und bietet Namespaces, Platzhalter und TTL.
- PyDispatcher scheint die Flexibilität in Bezug auf viele-zu-viele-Veröffentlichungen usw. zu betonen. Unterstützt schwache Referenzen.
- louie ist ein überarbeiteter PyDispatcher und sollte "in einer Vielzahl von Kontexten" arbeiten.
- pypydispatcher basiert auf (Sie haben es erraten ...) PyDispatcher und funktioniert auch in PyPy.
- django.dispatch ist ein umgeschriebener PyDispatcher "mit einer eingeschränkteren Oberfläche, aber höherer Leistung".
- pyeventdispatcher basiert auf dem Event-Dispatcher des Symfony-Frameworks von PHP.
- Der Dispatcher wurde aus django.dispatch extrahiert, wird aber ziemlich alt.
- Cristian Garcias EventManger ist eine sehr kurze Implementierung.
Andere:
- pluggy enthält ein Hook-System, das von
pytest
Plugins verwendet wird .
- RxPy3 implementiert das Observable-Muster und ermöglicht das Zusammenführen von Ereignissen, erneuten Versuchen usw.
- Die Signale und Slots von Qt sind bei PyQt
oder PySide2 erhältlich . Sie funktionieren als Rückruf, wenn sie im selben Thread verwendet werden, oder als Ereignisse (mithilfe einer Ereignisschleife) zwischen zwei verschiedenen Threads. Signale und Slots haben die Einschränkung, dass sie nur in Objekten von Klassen funktionieren, von denen abgeleitet ist
QObject
.
Ich habe es so gemacht:
Wie bei allem anderen, was ich gesehen habe, gibt es dafür kein automatisch generiertes Pydoc und keine Signaturen, was wirklich scheiße ist.
quelle
_bag_of_handlers
die eine Liste ist. Die Add-Methode der Klasse wäre einfachself._bag_of_handlers.append(some_callable)
. Die Feuermethode der Klasse würde eine Schleife durch die Tasche der Handler durchlaufen und die bereitgestellten Argumente und Warnungen an die Handler weitergeben und jeweils nacheinander ausführen.Wir verwenden einen EventHook, wie von Michael Foord in seinem Event-Muster vorgeschlagen :
Fügen Sie einfach EventHooks zu Ihren Klassen hinzu mit:
Wir haben die Funktionalität hinzugefügt, um alle Listener von einem Objekt zur Michaels-Klasse zu entfernen.
quelle
self.__handlers = [h for h in self._handlers if getattr(h, 'im_self', False) != obj]
Ich benutze zope.event . Es sind die nacktesten Knochen, die Sie sich vorstellen können. :-) Tatsächlich ist hier der vollständige Quellcode:
Beachten Sie, dass Sie beispielsweise keine Nachrichten zwischen Prozessen senden können. Es ist kein Nachrichtensystem, nur ein Ereignissystem, nicht mehr und nicht weniger.
quelle
Ich habe dieses kleine Skript in Valued Lessons gefunden . Es scheint genau das richtige Verhältnis von Einfachheit und Leistung zu haben, nach dem ich suche. Peter Thatcher ist der Autor des folgenden Codes (es wird keine Lizenzierung erwähnt).
quelle
Hier ist ein minimales Design, das gut funktionieren sollte. Was Sie tun müssen, ist einfach
Observer
in einer Klasse zu erben und anschließend zu verwendenobserve(event_name, callback_fn)
, um auf ein bestimmtes Ereignis zu warten. Immer wenn dieses bestimmte Ereignis irgendwo im Code ausgelöst wird (dhEvent('USB connected')
), wird der entsprechende Rückruf ausgelöst .Beispiel:
quelle
Ich habe eine
EventManager
Klasse erstellt (Code am Ende). Die Syntax lautet wie folgt:Hier ist ein Beispiel:
Ausgabe:
EventManger-Code:
quelle
Sie können einen Blick auf Pymitter ( Pypi ) werfen . Es handelt sich um einen kleinen Single-File-Ansatz (~ 250 loc), der "Namespaces, Platzhalter und TTL bereitstellt".
Hier ist ein einfaches Beispiel:
quelle
Ich habe eine Variation von Longpokes minimalistischem Ansatz gemacht, die auch die Signaturen sowohl für Anrufer als auch für Anrufer sicherstellt:
quelle
Wenn ich in pyQt codiere, verwende ich das QT-Sockets / Signal-Paradigma, dasselbe gilt für Django
Wenn ich asynchrone E / A-Vorgänge durchführe, verwenden Sie das native Auswahlmodul
Wenn ich einen SAX-Python-Parser verwende, verwende ich die von SAX bereitgestellte Ereignis-API. Es sieht also so aus, als wäre ich Opfer der zugrunde liegenden API :-)
Vielleicht sollten Sie sich fragen, was Sie von Event Framework / Modul erwarten. Meine persönliche Präferenz ist die Verwendung des Socket / Signal-Paradigmas von QT. Weitere Infos dazu finden Sie hier
quelle
Hier ist ein weiteres Modul zur Prüfung. Es scheint eine gute Wahl für anspruchsvollere Anwendungen zu sein.
quelle
Wenn Sie kompliziertere Dinge wie das Zusammenführen von Ereignissen oder das Wiederholen von Ereignissen ausführen möchten, können Sie das Observable-Muster und eine ausgereifte Bibliothek verwenden, die dies implementiert. https://github.com/ReactiveX/RxPY . Observables sind in Javascript und Java sehr verbreitet und für einige asynchrone Aufgaben sehr praktisch.
AUSGABE :
quelle
Wenn Sie einen Eventbus benötigen, der über Prozess- oder Netzwerkgrenzen hinweg funktioniert, können Sie PyMQ ausprobieren . Derzeit werden Pub / Sub, Nachrichtenwarteschlangen und synchroner RPC unterstützt. Die Standardversion funktioniert auf einem Redis-Backend, sodass Sie einen laufenden Redis-Server benötigen. Es gibt auch ein In-Memory-Backend zum Testen. Sie können auch Ihr eigenes Backend schreiben.
So initialisieren Sie das System:
Haftungsausschluss: Ich bin der Autor dieser Bibliothek
quelle
Sie können das
buslane
Modul ausprobieren .Diese Bibliothek erleichtert die Implementierung eines nachrichtenbasierten Systems. Es unterstützt den Ansatz von Befehlen (einzelner Handler) und Ereignissen (0 oder mehrere Handler). Buslane verwendet Anmerkungen vom Typ Python, um den Handler ordnungsgemäß zu registrieren.
Einfaches Beispiel:
Verwenden Sie zum Installieren der Busbahn einfach pip:
quelle
Vor einiger Zeit habe ich eine Bibliothek geschrieben, die für Sie nützlich sein könnte. Es ermöglicht Ihnen lokale und globale Listener, verschiedene Arten der Registrierung, Ausführungspriorität usw.
Schauen Sie sich pyeventdispatcher an
quelle