PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

Le pattern observer en utilisant des décorateurs

dimanche 14 octobre 2012 à 17:03

Nous avons vu précédemment que les décorateurs permettaient d’exécuter du code avant et après une fonction, sans modifier la fonction. La plupart du temps on retourne ainsi une nouvelle fonction avec un comportement différent.

Mais il existe d’autres usages pour les décorateurs, et notamment un qui est au cœur du fonctionnement de django-quicky: l’abonnement.

def evenement(nom):
 
    # on assure que la liste des events et callabcks est initialisae
    evenement.abonnements = getattr(evenement, 'abonnements', {})
 
    # on ajoute un moyen d'appeler tous les callbacks pour un event
    evenement.trigger = lambda e: [f(e) for f in evenement.abonnements[e]] 
 
    # définition du décorateur lui-même
    def decorateur(func):
 
        # on ajoute la fonction comme callback pour cet event
        evenement.abonnements.setdefault(nom, []).append(func)
 
        # et on retourne la fonction telle qu'elle, sans la modifier
        return func
 
    return decorateur

Ce morceaux de code s’utilise ainsi:

# a chaque fois qu'on met le decorateur
# la fonction est liae à un événement
@evenement('evenement1')
@evenement('evenement2')
def reagir_a_evenement(evenement):
    # la fonction doit acccepter l'evenement en paramètre
    print "Oh, evenement '%s' a eu lieu" % evenement
 
@evenement('evenement1')
def moi_aussi(evenement):
    print "Cool, moi aussi j'ai reagit a l'evenement '%s'" % evenement
 
# ici on déclenche l'événement sans raison
# mais dans du vrai code on le déclenche à la suite
# d'une action réelle
evenement.trigger('evenement1')
evenement.trigger('evenement2')

Ici c’est un exemple simplifié, mais le principe y est: chaque fois qu’on utilise un décorateur, on associe la fonction décorée à un nom (ici le nom de notre événement, mais dans django-quicky, c’est l’url). Et quand l’événement se produit, on appelle toutes les fonctions enregistrées, en leur passant l’objet événement (ici une simple string) en paramètres.

Avec ce design pattern appelé ‘observer’, on découple complètement le code qui déclenche un événement (la lecture d’un fichier, une erreur, un entrée utilisateur, etc) et le code qui réagit à cet événement (qui peut très bien être celui d’une lib complètement séparée).

Le décorateur Python est un moyen particulièrement pratique de déclarer un abonnement d’une fonction à un événement, et ne demande quasiment aucun effort de la part du développeur qui l’utilise à part d’avoir une fonction qui accepte les bons paramètres pour réagir à tous les événements que peuvent produire votre library.