Ce este o programare bună și curată bazată pe evenimente în Python? În prezent, mă confrunt cu ceea ce se numește ' Callback Hell ' și vreau să știu cum să o faceți corect.


Cel mai bun răspuns

Pe baza comentariilor de mai sus, aici este o strategie generală. Evident, detaliile contează foarte mult, desigur .

Practic veți avea două părți.

obiectul eveniment sau „ editor” este responsabil pentru menținerea unei liste cu toate funcțiile care ar trebui apelate atunci când se întâmplă un eveniment. Are o metodă fire() care trece peste lista respectivă și apelează pe rând toate funcțiile. Probabil ar trebui, de asemenea, să aibă metode de gestionare a listei (eliminarea unei funcții din listă nu mai este necesară).

Handlerele sau „ abonați” sunt funcții pe care le veți apela atunci când evenimentul se va întâmpla efectiv. Singurul aspect complicat este că trebuie să controlați semnătura handlerilor, astfel încât evenimentul să le poată apela fără a face nicio introspecție suplimentară.

Iată un exemplu extrem de minim:

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

Aceasta ar trebui să producă

example handler fired ("started",)

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

Principalele probleme de gestionare sunt: ​​

Tratarea excepțiilor. trebuie să decideți dacă gestionarul trebuie să fie sau nu în condiții de siguranță. Dacă nu, codul de mai sus este mai mult sau mai puțin OK, dar dacă nu doriți ca un abonat rău să aducă în jos întregul program, trebuie să decideți cum să faceți față unei excepții și dacă să „dezabonați” sau nu administratorul care a încălcat .

Managementul memoriei. Exemplul folosește doar o funcție ca handler; dacă nu eliminați () funcția pe care nu trebuie să o gestionează-l pe toată durata vieții. Cu toate acestea, veți dori adesea să aveți fie obiecte apelabile, fie funcții de membru ca handler / abonați. Dacă da, probabil că trebuie să utilizați referințe slabe, mai degrabă decât setul naiv folosit în exemplu – în caz contrar, gestionarii de evenimente vor ajunge să păstreze obiectele în viață după ce ar fi trebuit să fi ieșit din sfera de aplicare și ar trebui să fie colectate la gunoi.

Metadate: Exemplul include un pic de metadate – șirul care este transmis ca Event() s sunt declarate. Aplicația dvs. ar putea avea nevoie de mai mult sau mai puțin decât aceasta. Mai multe metadate înseamnă de obicei mai multe cuplări, ceea ce nu este ideal. Cu toate acestea, dacă gestionarele dvs. au toate semnătura (*args, **kwargs) puteți transmite oricând datele și apoi puteți decide la nivel de gestionare dacă vă pasă sau nu.

Bună referință : Modelul de observator din Python

Exemplu al ideii de bază în acțiune: theodox / mGui

Răspuns

Dacă accesați site-ul web tornado web framework, acestea au o pagină de exemple. Pe pagina respectivă există un exemplu de cod de aplicație de chat. Este foarte scurt și ușor de înțeles.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *