Dans cet article, nous allons voir à quel point les décorateurs sont puissants. Si vous êtes nouveau à Python (et peut-être même si vous ne l’êtes pas), vous n’avez probablement jamais entendu parler de cette construction. C’est quelque chose de spécifique à Python, qui permet de définir un comportement général commun à de nombreuses méthodes dans une fonction séparée. Moi-même, j’ai découvert cela que tout récemment !
Par exemple, supposons que nous ayons les méthodes suivantes :
def sum(a, b): return a+b def subtract(a, b): return a-b
Nous voulons maintenant imprimer le résultat dans la console, avant de le renvoyer. Que devons-nous faire ? La première idée est d’ajouter une instruction print dans toutes les fonctions. Mais que se passe-t-il si nous décidons de sauvegarder le résultat dans un fichier ? Nous devrions à nouveau modifier toutes les fonctions.
Au lieu de cela, nous pouvons créer un décorateur log_result
et l’ajouter aux méthodes :
@log_result def sum(a, b): return a+b @log_result def subtract(a, b): return a-b
Et maintenant, si nous voulons changer l’endroit où nous écrivons la sortie, nous devons juste changer le code dans log_result
.
Qu’est-ce qu’un décorateur (decorator) ?
Nous avons vu comment les décorateurs peuvent être utilisés, mais qu’est-ce qu’un décorateur exactement ?
Pour vous donner une définition formelle,
A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.
En traduction libre :
Un décorateur est une fonction qui prend une autre fonction et étend le comportement de cette dernière sans la modifier explicitement.
Décortiquons cela morceau par morceau.
Tout d’abord, un décorateur est une fonction qui prend une autre fonction comme paramètre : cela signifie que nous définirons le décorateur log_result
comme :
def log_result(func):
Ensuite, nous devons modifier cette fonction et retourner la version modifiée.
Nous pouvons donc créer une fonction interne (que j’ai appelée inner
pour simplifier) qui exécute func
, imprime le résultat et renvoie enfin cette valeur :
def log_result(func): def inner(): res = func() print(res) return res
Enfin, le décorateur doit retourner la fonction modifiée :
def log_result(func): def inner(): res = func() print("The result is ", res) return res return inner
Nous avons créé notre premier décorateur ! Enfin, pas vraiment. Il ne fonctionne que si la fonction à laquelle nous l’ajoutons n’a pas de paramètres. Par exemple :
@log_result def get_even_digits(): return [0, 2, 4, 6, 8]
Lorsque nous appelons cette fonction, le journal s’imprime à l’écran :
>>> l = get_even_digits() The result is [0, 2, 4, 6, 8]
Cependant, si nous essayons de l’utiliser avec les méthodes sum et subtract de la version précédente, le code ne s’exécutera pas correctement.
Le problème est que nous n’avons pas donné à la fonction modifiée la possibilité de recevoir les paramètres qui devraient être passés à func
. Heureusement, ce problème peut être résolu facilement. Nous allons redéfinir inner
comme suit :
def log_result(func): def inner(**kwargs): res = func(kwargs) print("The result is ", res) return res return inner
Maintenant, inner
peut obtenir n’importe quel nombre de paramètres, et les passer directement à la fonction. Nous l’avons fait !
>>>s = sum(3, 5) The result is 8 >>>d = subtract(8,5) The result is 3
Décorateurs avec paramètres
Enfin, nous pouvons vouloir passer des paramètres supplémentaires au décorateur. Par exemple, nous pouvons vouloir imprimer également un nom avec le résultat, afin de savoir de quelle opération provient ce journal.
Pour ce faire, nous devons modifier légèrement la fonction :
def log_with_name(name): def log_result(f): def inner(x): res = f(x) print(name + ": " + str(res)) return inner return log_result
Voyons ce qui se passe. La fonction log_with_name
prend la chaîne du nom et renvoie le décorateur qui sera ensuite appliqué à une fonction.
Il peut être utilisé exactement comme avant :
@log_with_name("Sum") def sum(a, b): return a+b @log_with_name("Difference") def subtract(a, b): return a-b
Et le résultat sera :
>>> s = sum(3, 5) Sum: 8 >>> d = subtract(8, 3) Difference: 5
Conclusion
Merci d’avoir lu jusqu’au bout ! Voici d’autres ressources sur les décorateurs :