Comprendre Les Décorateurs Python
Mise à jour :
Les décorateurs Python, c’est un peu comme ajouter une couche de vernis à vos fonctions : ils permettent de modifier ou d’enrichir leur comportement, sans toucher à leur code. En gros, ils prennent une fonction, l’enrobent de logique supplémentaire et renvoient une version boostée. Que vous vouliez mesurer le temps d’exécution d’une méthode, vérifier des permissions ou simplement ajouter un peu de magie, les décorateurs sont vos alliés. Et le meilleur ? Une fois que vous les maîtrisez, vous ne pourrez plus vous en passer !
Comment fonctionnent les fonctions en Python
Pour bien comprendre les décorateurs, il faut d’abord se plonger dans un concept clé de Python : les fonctions sont des objets de première classe. Ça veut dire quoi ? Tout simplement que les fonctions en Python sont comme n’importe quel autre objet : elles peuvent être stockées dans des variables, passées en argument à d’autres fonctions, ou même être retournées comme résultats.
Prenons un exemple simple pour illustrer cela :
Ici, salutation
devient un alias de dire_bonjour
. Les deux références
pointent vers le même objet fonction.
On peut aussi passer une fonction comme argument à une autre. C’est ici que la magie des décorateurs commence à apparaître.
Résultat ? La fonction dire_bonjour
est exécutée depuis executer_fonction
.
Cela ouvre la voie à des opérations comme ajouter de la logique avant ou après
l’exécution d’une fonction.
Une fonction peut aussi en retourner une autre. Ce comportement est crucial pour comprendre comment les décorateurs modifient des fonctions.
Ici, faire_salut
retourne une nouvelle fonction, message
, que l’on peut
appeler indépendamment.
Maintenant, combinons ces idées : une fonction peut à la fois recevoir une autre fonction et en retourner une. C’est littéralement ce que fait un décorateur.
Ici, mon_decorateur
enveloppe dire_au_revoir
dans un nouveau comportement.
La fonction retournée, wrapper
, contient les actions avant et après.
Comprendre que les fonctions sont des objets de première classe est essentiel pour utiliser les décorateurs. Cela permet de saisir comment ils interceptent et enrichissent des fonctions existantes. Une fois cette idée en tête, les décorateurs deviennent un outil incroyablement puissant pour optimiser votre code !
Créer un décorateur simple
Maintenant que l’on sait que les fonctions en Python peuvent être passées et retournées comme des objets, créons un décorateur basique. Un décorateur est, en gros, une fonction qui prend une autre fonction en entrée, lui ajoute du code avant ou après, et retourne une nouvelle fonction “enrichie”.
Structure de base d’un décorateur
Voici la structure classique d’un décorateur :
Dans cet exemple, mon_decorateur
enveloppe une fonction avec un “emballage”
(wrapper
) contenant du code supplémentaire.
Utilisation d’un décorateur
Supposons que nous ayons une fonction dire_bonjour
que nous voulons enrichir.
Voici comment l’appliquer manuellement :
Cela produit :
Plutôt cool, non ? Mais il y a une façon encore plus simple d’appliquer un
décorateur : utiliser la syntaxe @
.
La syntaxe @
pour simplifier
Python fournit une syntaxe dédiée pour appliquer un décorateur. Il suffit
d’utiliser le symbole @
avant le nom du décorateur :
Cette syntaxe est équivalente à l’exemple précédent, mais bien plus lisible.
Décorer des fonctions avec des arguments
Et si notre fonction avait des arguments ? Pas de problème, il suffit de passer
ces arguments à func
dans le wrapper :
Sortie :
Le *args
et **kwargs
permettent de gérer n’importe quel nombre d’arguments
positionnels ou nommés. C’est indispensable pour des fonctions génériques.
Pourquoi utiliser des décorateurs ?
Créer un décorateur permet de réutiliser du code commun, comme ajouter des logs, mesurer le temps d’exécution, ou gérer des permissions. Par exemple, voici un décorateur pour mesurer la durée d’une fonction :
Sortie :
Empilement de décorateurs
Saviez-vous que vous pouvez appliquer plusieurs décorateurs à une même fonction ? Oui, Python permet ce qu’on appelle l’empilement de décorateurs, et c’est à la fois pratique et puissant. L’idée est simple : chaque décorateur s’applique successivement, dans l’ordre où ils sont définis, pour enrichir votre fonction étape par étape.
Comment empiler des décorateurs
Pour empiler des décorateurs, il suffit de les écrire les uns au-dessus des
autres, avec le symbole @
. Voici un exemple simple :
Sortie :
Ordre d’exécution
L’ordre des décorateurs est important. Dans l’exemple ci-dessus, decorateur_2
est appliqué avant decorateur_1
car Python traite les décorateurs du bas
vers le haut.
Autrement dit :
ma_fonction
est décorée pardecorateur_2
.- Puis, le résultat est à nouveau décoré par
decorateur_1
.
Exemple pratique : logs et chronométrage
Imaginons que vous souhaitiez à la fois ajouter des logs et mesurer le temps d’exécution d’une fonction. Voici comment faire :
Sortie :
Étendre l’empilement aux méthodes de classes
Les décorateurs empilés fonctionnent aussi très bien sur des méthodes de classes. Par exemple, vous pouvez combiner des décorateurs pour vérifier les permissions et ajouter des logs :
Sortie :
Décorateurs dans des classes
Les décorateurs ne sont pas réservés aux fonctions globales. Vous pouvez aussi les appliquer aux méthodes et aux propriétés d’une classe pour ajouter des comportements ou simplifier la gestion de vos données. C’est une fonctionnalité puissante pour structurer un code objet propre et réutilisable.
En Python, il existe des décorateurs intégrés spécifiques pour gérer les méthodes dans une classe :
@staticmethod
: indique qu’une méthode n’a pas accès à l’instance ou à la classe elle-même. C’est une fonction “indépendante” dans une classe.@classmethod
: transforme une méthode pour qu’elle reçoive la classe comme premier argument au lieu de l’instance (cls
au lieu deself
).
Exemple avec @staticmethod
Une méthode statique est utile pour des fonctions qui ne dépendent pas des attributs de l’instance ou de la classe.
Exemple avec @classmethod
Une méthode de classe permet de travailler avec la classe elle-même.
Décorateurs pour les propriétés
Un autre usage fréquent des décorateurs dans les classes est la gestion des
propriétés avec @property
. Cela permet de définir des getters et
setters sans appeler explicitement des méthodes.
Ici, @property
permet d’accéder à l’attribut _nom
comme si c’était une
propriété publique tout en gardant le contrôle sur sa validation.
Les décorateurs de Click
Dans un autre chapitre, nous avons vu comment les décorateurs enrichissent les fonctions. Click exploite cette puissance pour simplifier la création de CLI (Command Line Interface). En voici la liste :
@click.command
: transforme une fonction en commande CLI.@click.option
: ajoute des options avec préfixe (--nom
).@click.argument
: gère les arguments positionnels.@click.group
: regroupe plusieurs commandes sous une même interface.
Conclusion
Les décorateurs Python sont une solution élégante pour enrichir vos fonctions et simplifier votre code. Qu’il s’agisse de valider des données, de mesurer des performances ou de structurer des CLI avec des outils comme Click, ils offrent une modularité et une lisibilité incomparables.
En maîtrisant les décorateurs, vous pouvez écrire un code plus propre et plus maintenable, tout en réduisant les répétitions inutiles. Les perspectives sont vastes : frameworks, outils d’automatisation ou optimisation de vos propres projets. Lancez-vous, et découvrez à quel point les décorateurs peuvent transformer votre manière de coder !