Les decorateurs de python

Voilà simplement un petit article sur les decorateurs de python. C'est en qqsorte ; mes notes, mais si ça peut servir à d'autres, tant mieux.

L'idée étant de présenter les decorateurs, du plus simple au plus complexe

Le decorateur le plus simple 'dec1':

A exemple 1:

def dec1(func):
    return func

@dec1
def fonction(a):
    return a*3

Qui est, en fait, une fonction qui reçoit en paramètre une fonction, et retourne une fonction.

Il est alors techniquement possible de retourner une autre fonction que celle passée en paramètre, et ainsi effectuer une substitution de fonction.

A exemple 2:

def dec2(func):
    def give(a):
        print 10*a
    return give

@dec2
def fonction(a):
    return a*3

Plutôt que de retourner 'func' (la fonction d'origine), on en retourne une autre, qui a la même signature.

Maintenant, un cas plus générique, et certainement plus utile. Car il retourne une fonction acceptant toutes les signatures possibles (ce décorateur peut être utilisé sur d'autres fonctions)

A exemple 3:

def dec3(func):
    def gave(*k,**a):
        print "BEGIN"
        a= func(*k,**a)
        print "END"
        return a
    return gave

@dec3
def fonction(a):
    return a*3

De plus, il execute la fonction passée en paramètre. C'est ce genre de décorateur qui est utilisé pour logguer des appels de fonction.

Mais on peut également passé des paramètres à un décorateur, c'est le cas de l'exemple suivant :

A exemple 4:

def dec4(mot):
    def dec(func):
        def gave(*k,**a):
            print "BEGIN",mot
            a= func(*k,**a)
            print "END",mot
            return a
        return gave
    return dec

@dec4("log")
def fonction(a):
    return a*3

Le decorateur reçoit le paramètre et renvoi le decorateur de "base", qui peut alors utilisé ce paramètre en son sain.

Cet exemple montre bien le chainage d'objet "callable", et l'on obtiendrait le même résultat en appelant "fonction" ainsi :

A exemple 5:

dec4("toto")(fonction)(12)

En fait, on peut retourner n'importe quel objet du moment qu'il soit "callable" (qui implémente call), comme sur l'exemple suivant où le decorateur renvoi une instance d'une classe :

A exemple 6:

def dec5(func):
    class ACallable:
        def __call__(self,a):
            print "call with ",a
    return ACallable()

@dec5
def fonction(a):
    return a*3

Un autre exemple dans le même genre où l'on retourne une classe. Ce qui aura pour conséquence, à l'appel de "fonction" de retourner une instance de cette classe.

A exemple 7:

def dec6(func):
    class AClass:
        def __init__(self,*a,**k):
            print "call with ",a,k
    return AClass

@dec6
def fonction(a):
    return a*3

Je vous laisse imaginer les possibilités de design de code ;-)

log in

manatlan