Décorateurs¶
Les décorateurs sont des fonctions ou des classes qui permettent de modifier le comportement d’une autre fonction (ou classe). Les décorateurs sont utiles lorsque l’on souhaite qu’un certain nombre de fonctions effectuent des tâches communes comme par exemple donner leur temps d’exécution. On appelle un décorateur de la manière suivante.
@decorateur
def fonction():
pass
Le code précédent a le même comportement que le code suivant:
def fonction():
pass
fonction = decorateur(fonction)
Ainsi, fonction
devient l’objet retournée par
decorateur(fonction)
. Le décorateur doit donc être un .
Plus d’informations : Stack Overflow
En tant que classe¶
Une façon d’implémenter un décorateur est d’utiliser les classes. La
fonction décorée deviendra alors une instance de la classe de ce
décorateur. Il faut obligatoirement définir la méthode __call__()
pour pouvoir rendre cette instance callable.
Exemple : On considère ici un décorateur qui compte le nombre d’appels de la fonction décorée.
class Compteur:
def __init__(self, f):
self.call = 0
self.f = f
def __call__(self, *args, **kwargs):
self.call += 1
print("La fonction {} a été appelée {} fois.".format(self.f.__name__, self.call))
return self.f(*args, **kwargs)
En tant que fonction¶
Comme un décorateur est un objet callable qui n’a d’autre utilité que d’être appelé, il est aussi logique de le définir en tant que fonction.
Exemple : Même décorateur que précédemment mais en l’implémentant en tant que fonction.
def compteur(f):
def wrapper(*args, **kwargs):
wrapper.call += 1
print("La fonction {} a été appelée {} fois.".format(f.__name__, wrapper.call))
return f(*args, **kwargs)
wrapper.call = 0
return wrapper
Dans cet exemple, on assigne à wrapper
un attribut de fonction (on
peut le faire, puisqu’une fonction est un objet – de la classe
function
). On le définit après avoir défini cette fonction.
Les deux décorateurs précédents donnent ce comportement:
>>> @compteur
... def func():
... return "func got called!"
...
>>> func()
La fonction func a été appelée 1 fois.
'func got called!'
>>> func()
La fonction func a été appelée 2 fois.
'func got called!'
Décorateurs à paramètres¶
On peut faire en sorte que le décorateur prenne un ou plusieurs paramètres. Dans ce cas, il faut définir le décorateur à l’intérieur d’une clôture qui prend en argument ces différents paramètres.
Exemple : On veut retourner une erreur quand la fonction retourne une valeur trop élevée.
def depasse_max(max):
def deco(f):
def wrapper(*args, **kwargs):
n = f(*args, **kwargs)
if n > max:
print("Maximum {} dépassé.".format(max))
return
return n
return wrapper
return deco
Ces deux syntaxes sont équivalentes:
# Syntaxe 1
@depasse_max(10)
def demande_nombre():
n = int(input("Entrer un nombre : "))
return n
# Syntaxe 2
def demande_nombre():
n = int(input("Entrer un nombre : "))
return n
demande_nombre = depasse_max(10)(demande_nombre)
Cela permet de faire
>>> demande_nombre()
Entrer un nombre : 11
Maximum 10 dépassé.