Quest-ce quune programmation événementielle bonne et propre en Python? Je vis actuellement ce quon appelle ' Callback Hell ' et que vous voulez savoir comment le faire correctement.


Meilleure réponse

Sur la base des commentaires ci-dessus, voici une stratégie générale. Évidemment, les détails comptent beaucoup, bien sûr .

En gros, vous aurez deux parties.

Lobjet événement ou «  éditeur » est responsable de maintenir une liste de toutes les fonctions qui doivent être appelées lorsquun événement se produit. Il a une méthode fire() qui boucle sur cette liste et appelle toutes les fonctions à tour de rôle. Il devrait probablement aussi avoir des méthodes pour gérer la liste (en supprimant une fonction de la liste, ce nest pas nécessaire).

Les gestionnaires ou «  abonnés » sont des fonctions que vous « allez appeler lorsque lévénement se produit réellement. Le seul point délicat est que vous devez contrôler la signature des gestionnaires pour que lévénement puisse les appeler sans faire aucune introspection supplémentaire.

Voici un exemple ultra minimal:

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

Cela devrait produire

example handler fired ("started",)

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

Les principaux problèmes de gestion sont:

Gestion des exceptions. vous devez décider si le gestionnaire doit être protégé contre les exceptions ou non. Si ce nest pas le cas, le code ci-dessus est plus ou moins OK, mais si vous ne voulez pas quun mauvais abonné arrête tout le programme, vous devez décider comment faire face à une exception et si vous souhaitez ou non «désabonner» le gestionnaire incriminé .

Gestion de la mémoire. Lexemple nutilise quune fonction comme gestionnaire; à moins que vous ne supprimiez () la fonction, vous navez pas à gérer sa durée de vie. Cependant, vous voudrez souvent avoir soit des objets appelables, soit des fonctions membres comme gestionnaires / abonnés. Si tel est le cas, vous devrez probablement utiliser des références faibles plutôt que lensemble naïf utilisé dans lexemple – sinon les gestionnaires dévénements finiront par garder les objets en vie après quils auraient dû être hors de portée et devraient être récupérés.

Métadonnées: Lexemple comprend un peu de métadonnées – la chaîne qui est transmise en tant que Event() s sont déclarés. Votre application peut nécessiter plus ou moins que cela. Plus de métadonnées signifie généralement plus de couplage, ce qui nest pas idéal. Cependant, si vos gestionnaires ont tous la signature (*args, **kwargs) , vous pouvez toujours transmettre les données et ensuite décider au niveau du gestionnaire si cela vous intéresse ou non.

Bonne référence : Le modèle dobservateur en Python

Exemple de lidée de base en action: theodox / mGui

Réponse

Si vous allez sur le site Web du framework web tornado, ils ont une page dexemples. Sur cette page, il y a un exemple de code dapplication de chat. Cest vraiment court et compréhensible.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *