Wat is goed en schoon, gebeurtenisgestuurd programmeren in Python? Ik ervaar momenteel wat ' s genaamd ' Callback Hell ' en willen weten hoe je het goed moet doen.


Beste antwoord

Op basis van de bovenstaande opmerkingen is hier een algemene strategie. Uiteraard zijn de details natuurlijk erg belangrijk .

In wezen heb je twee delen.

Het gebeurtenisobject of de “ uitgever” is verantwoordelijk voor het bijhouden van een lijst met alle functies die moeten worden aangeroepen als er een gebeurtenis plaatsvindt. Het heeft een fire() -methode die door die lijst loopt en alle functies beurtelings aanroept. Het zou waarschijnlijk ook methoden moeten hebben om de lijst te beheren (het verwijderen van een functie uit de lijst is niet langer nodig).

De handlers of “ subscribers” zijn functies die u “gaat oproepen wanneer de gebeurtenis daadwerkelijk plaatsvindt. Het enige lastige daar is dat je de handtekening van de handlers moet controleren, zodat het evenement ze kan aanroepen zonder enige extra introspectie.

Hier is een ultra minimaal voorbeeld:

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

Dat zou moeten opleveren

example handler fired ("started",)

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

De belangrijkste beheerproblemen zijn:

Afhandeling van uitzonderingen. je moet beslissen of de handler uitzonderingsveilig moet zijn of niet. Als de bovenstaande code niet min of meer in orde is, maar als u niet wilt dat een slechte abonnee het hele programma naar beneden haalt, moet u beslissen hoe u met een uitzondering om moet gaan en of u de overtredende handler al dan niet wilt uitschrijven .

Geheugenbeheer. Het voorbeeld gebruikt alleen een functie als een handler; tenzij u de functie verwijdert () hoeft u dit niet te doen beheer de levensduur ervan. U wilt echter vaak ofwel oproepbare objecten of ledenfuncties als handlers / abonnees hebben. Als dit het geval is, moet u waarschijnlijk zwakke referenties gebruiken in plaats van de naïeve set die in het voorbeeld wordt gebruikt – anders zullen de gebeurtenishandlers objecten in leven houden nadat ze buiten het bereik hadden moeten vallen en als afval moeten worden verzameld.

Metadata: Het voorbeeld bevat een klein beetje metadata – de string die wordt doorgegeven als de Event() s worden verklaard. Uw aanvraag heeft mogelijk meer of minder nodig. Meer metadata betekent meestal meer koppeling, wat niet ideaal is. Als uw handlers echter allemaal de (*args, **kwargs) -handtekening hebben, kunt u altijd de gegevens doorgeven en vervolgens op handlerniveau beslissen of u er al dan niet om geeft.

Goede referentie : The Observer Pattern in Python

Voorbeeld van het basisidee in actie: theodox / mGui

Antwoord

Als je naar de tornado web framework-website gaat, hebben ze een voorbeeldpagina. Op die pagina staat een voorbeeld van een chatapplicatiecode. Het is tamelijk kort en begrijpelijk.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *