Python Les décorateurs démystifiés

Ce wiki a été archivé en 2018.

Le nouveau wiki se trouve à: ressources.labomedia.org

Les fonctionnalités sont désactivées: vous pouvez faire une recherche sur Google site:https://wiki.labomedia.org et découvrir La Labomedia.

De Centre de Ressources Numériques - Labomedia
Aller à : navigation, rechercher

Les décorateurs Python

Traduction libertaire de Les décorateurs python démystifiés

En python, tout est objet les fonctions aussi!

Les fonctions

Tout d'abord, nous allons comprendre ce qu'est une fonction en python.

def hi(name="martin"):
    return "hi "+name


print hi()
Retourne:
hi martin

Nous pouvons assigner une fonction à une variable soit greet = hi, hi est sans les parenthèses car nous n'appelons pas la fonction hi, nous assignons la fonction hi à la variable greet.
print greet()
Retourne:
hi martin

Que se passe-t-il si nous détruisons l'ancienne fonction hi ?
del hi
print hi()

Retourne:
NameError


print greet()
Retourne:
hi martin

Une fonction à l'intérieur d'une fonction

En Python, nous pouvons définir des fonctions à l'intérieur d'autres fonctions. Vous pourriez vous demander quelle sorcellerie est cela ! Permettez-moi de l'expliquer avec un exemple.

def hi(name="martin"):
    print "now you are inside the hi() function"

    def greet():
        return "now you are in the greet() function"

    def welcome():
        return "now you are in the welcome() function"

    print greet()
    print welcome()
    print "now you are back in the hi() function"


hi()
Retourne:
now you are inside the hi() function
now you are in the greet() function
now you are in the welcome() function
now you are back in the hi() function


greet()
Retourne:
NameError: name 'greet' is not defined

Alors maintenant, nous savons que nous pouvons définir des fonctions dans d'autres fonctions, et que nous pouvons faire des nids de fonctions. Autre point important, les fonctions peuvent retourner aussi une fonction.

Récupérer des fonctions depuis l'intérieur d'une fonction

Il ne est pas nécessaire d'exécuter une fonction dans une autre fonction, nous pouvons revenir comme une sortie ainsi.

def hi(name="martin"):
    def greet():
        return "now you are in the greet() function"

    def welcome():
        return "now you are in the welcome() function"

    if name == "martin":
        return greet
    else:
        return welcome

a = hi()


print a
Retourne:
<function greet at 0x7f2143c01500>

Cela montre que `a` pointe vers la fonction greet() dans hi()
print a()
Retourne:
now you are in the greet() function

Dans le cas if/else, nous retournons greet et welcome, et non pas greet() et welcome(). Pourquoi ? Parce que quand vous mettez des parenthèses, la fonction est exécutée alors que si vous ne mettez pas parenthèses, elle est peut être affectée à d'autres variables sans l'exécuter. Lorsque nous écrivons:
a = hi()
hi() est exécutée et parce que le nom est martin par défaut, la fonction greet est retournée. Si nous changeons la déclaration:
a = hi(name="dupond")
alors la fonction welcome vous sera retournée.
Nous pouvons également faire:
print hi()()
Retourne:
now you are in the greet() function

Donner une fonction comme argument à une autre fonction

Jetons un coup d'oeil à cet exemple:

def hi():
    return "hi martin!"

def doSomethingBeforeHi(func):
    print "Je fais quelque chose d'ennuyeux avant d'exécuter hi()"
    print func()


doSomethingBeforeHi(hi)
Retourne:
Je fais quelque chose d'ennuyeux avant d'exécuter hi()
hi martin!

Félicitations! Vous avez toutes les connaissances nécessaires pour vous donner les droit de dresseur de décorateurs !
Voici une courte définition:
Les décorateurs permettent d'exécuter du code avant ou après la fonction décorée.

Votre premier décorateur

Vous avez déjà écrit votre premier décorateur! Savez-vous quand ? Dans le dernier exemple, nous avons effectivement fait un décorateur !
Modifions le décorateur précédent pour avoir un programme un peu plus utilisable:

def a_new_decorator(a_func):
    def wrapTheFunction():
        print "Je fais quelque chose d'ennuyeux avant d'exécuter a_func()"
        a_func()
        print "Je fais quelque chose d'ennuyeux après avoir exécuter a_func()"
    return wrapTheFunction

def a_function_requiring_decoration():
    print "Je suis une fonction qui a besoin de decoration pour enlever ma mauvaise odeur"


a_function_requiring_decoration()
Retourne:
Je suis une fonction qui a besoin de decoration pour enlever ma mauvaise odeur

Maintenant a_function_requiring_decoration est emballé(wrapped) par wrapTheFunction()

def a_new_decorator(a_func):
    def wrapTheFunction():
        print "Je fais quelque chose d'ennuyeux avant d'exécuter a_func()"
        a_func()
        print "Je fais quelque chose d'ennuyeux après avoir exécuter a_func()"
    return wrapTheFunction

def a_function_requiring_decoration():
    print "Je suis une fonction qui a besoin de decoration pour enlever ma mauvaise odeur"

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)


a_function_requiring_decoration()
Retourne:
Je fais quelque chose d'ennuyeux avant d'exécuter a_function_requiring_decoration()
Je suis une fonction qui a besoin de decoration pour enlever ma mauvaise odeur
Je fais quelque chose d'ennuyeux après avoir exécuter a_function_requiring_decoration()

Nous avons juste appliqué les principes déjà appris. C'est exactement ce que font les décorateurs en python! Ils enveloppent une fonction et modifient son comportement dans un sens ou dans l'autre.

Syntaxe d'un décorateur

Maintenant, vous vous demandez peut-être pourquoi nous n'avons pas utilisé l' @ n'importe où dans notre code ? C'est juste la manière courte de faire une fonction décorée. Voici comment nous aurions pu exécuter l'exemple de code précédent en utilisant @.

@a_new_decorator
def a_function_requiring_decoration():
    print "Je suis une fonction qui a besoin de decoration pour enlever ma mauvaise odeur"


a_function_requiring_decoration()
Retourne:
Je fais quelque chose d'ennuyeux avant d'exécuter a_function_requiring_decoration()
Je suis une fonction qui a besoin de decoration pour enlever ma mauvaise odeur
Je fais quelque chose d'ennuyeux après avoir exécuter a_function_requiring_decoration()

@a_new_decorator est juste une manière courte de dire:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

Les décorateurs démystifiés

J'espère que vous avez maintenant une compréhension de base de la façon dont les décorateurs travaillent en Python. En outre, nous pouvons chaîner deux ou plus de deux décorateurs !
Par exemple:

def pain(func): # l'argument est une fonction
    def wrapper():
        print "</------\>"
        func()
        print "<\______/>"
    return wrapper # wrapper est une fonction

def ingredients(func): # l'argument est une fonction
    def wrapper():
        print "!tomate!"
        func()
        print "~salade~"
    return wrapper # wrapper est une fonction

def sandwich(food="--steak--"):
    print food


sandwich()
Retourne:
--steak--


pain(ingredients(sandwich)
Retourne:
</------\>
!tomate!
--steak--
~salade~
<\______/>

Dans sandwich = pain(ingredients(sandwich)), les sandwich sont des fonctions !

L'argument de la fonction est une fonction

def ingredients(func):
def pain(func):


définissent des fonctions dont l'argument est une fonction, func sans parenthèses puisqu'on ne l'exécute pas.

Exemple d'utilisation

Dans l'exemple suivant, e-satis fait vraiment un excellent travail en montrant comment les décorateurs sont utilisés.

Nous pouvons exécuter l'exemple précédent comme ceci:

@pain
@ingredients
def sandwich(food="--steak--"):
    print food


sandwich()
Retourne:
</------\>
!tomate!
--steak--
~salade~
<\______/>

Ordre des décorateurs

L'ordre dans lequel vous utilisez les décorateurs importe et vous pouvez changer le comportement d'ensemble de votre fonction décorée si elles ne sont pas exécutées dans l'ordre prévu.

Supposons que vous écriviez ceci:

@ingredients
@pain
def sandwich(food="--steak--"):
    print food


sandwich()
Retourne:
!tomate!
</------\>
--steak--
<\______/>
~salade~

Personne ne veut un sandwich à la tomate sur le dessus et de la salade sur le fond. Cela démontre pourquoi vous ne devriez pas mélanger la disposition des décorateurs, sinon vous aurez à payer le prix. Dans notre cas, nous avons payé le prix en gachant notre beau sandwich.

Mathématique: composition de fonctions

Soient X, Y et Z trois ensembles quelconques. Soient deux fonctions:

f:X --> Y

et

g:Y --> Z.

On définit la composée de f par g, notée g o f par

quelque soit x de X, (g o f)(x) = g(f(x))

On applique ici f à l'argument x, puis on applique g au résultat.

On obtient ainsi une nouvelle fonction g o f: X --> Z

La notation g o f se lit « g rond f ».

Un décorateur crée une fonction de fonction, (g o f)(x) qui est différente de (f o g)(x).