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. |
Sommaire
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).