Les Python De­co­ra­tors vous per­met­tent d’améliorer votre influence sur les fonc­tion­na­li­tés de base d’une fonction sans pour autant modifier le code source sur lequel elle se fonde.

Dé­co­ra­teurs de fonction : de quoi s’agit-il et à quoi servent-ils ?

L’uti­li­sa­tion des Python De­co­ra­tors n’est pas abordée en détail dans la plupart des tutoriels Python. Vous vous demandez pourquoi ? Pour com­prendre les dé­co­ra­teurs de fonction, il est d’abord né­ces­saire de bien maîtriser les fonctions en elles-mêmes. Dans le code, les Python De­co­ra­tors sont re­con­nais­sables grâce à leur propre opérateur Python : il s’agit du symbole « @ », suivi du nom du dé­co­ra­teur de fonction.

Note

Si vous voulez en savoir plus sur les tech­niques de pro­gram­ma­tion avancée avec Python, consultez les articles suivants :

L’exemple de code suivant présente la syntaxe de base d’un appel du Python Decorator, sans qu’aucune fonc­tion­na­lité ne soit toutefois im­plé­men­tée :

@decorator
def fonction():
 pass
Python

Dans cet exemple, le code en­re­gis­tré sous « decorator » serait exécuté en cas d’appel de la fonction nommée « fonction ».

Souvent, les dé­co­ra­teurs de fonction sont également utilisés dans le cadre de la pro­gram­ma­tion orientée objet avec Python. Il existe par exemple un dé­co­ra­teur Python Property, utilisé comme un équi­valent des méthodes « getter » et « setter » dans d’autres langages de pro­gram­ma­tion.

Conseil

Le langage de pro­gram­ma­tion Python est parfait pour les projets Web, entre autres grâce à ses solutions pratiques (comme les dé­co­ra­teurs de fonction). L’outil Deploy Now, proposé par IONOS, se prête aussi très bien à la réa­li­sa­tion de projets Web. L’outil Deploy Now vous permet de créer et de déployer fa­ci­le­ment votre projet grâce à GitHub, de façon à bé­né­fi­cier d’une vue d’ensemble sur votre projet à tout moment.

Python De­co­ra­tors : uti­li­sa­tion

Améliorer les fonc­tion­na­li­tés de base avec les Python De­co­ra­tors

Dans la plupart des cas, les Python De­co­ra­tors sont utilisés pour améliorer les fonc­tion­na­li­tés de base d’une fonction. Cette solution peut s’avérer pratique si vous avez recours à la même fonction de base dans le cadre de dif­fé­rents cas d’uti­li­sa­tion et que vous souhaitez l’améliorer dans certaines si­tua­tions seulement. Vous trouverez ci-dessous un exemple de code simple, mais prêt à être exécuté. Découvrez comment utiliser un Python Decorator pour améliorer une fonc­tion­na­lité :

def dec(fonction):
 def foo(x):
  print("Avant l'appel de la fonction de" + fonction.__nom__)
  fonction(x)
          print("Avant l'appel de la fonction de" + fonction.__nom__)
 return foo
@dec
def bar(y):
 print("Appel de la fonction bar avec la valeur" + str(y))
bar("Test")
Python

Dans cet exemple de code, nous com­men­çons par créer le dé­co­ra­teur nommé « dec » ; celui-ci contient une fonction portant le nom « foo ». Comme vous pouvez le voir, le dé­co­ra­teur de fonction n’est fi­na­le­ment rien de plus qu’une fonction « wrapper » autonome. Dans notre cas, elle contient une autre fonction nommée « foo ». Dans cette fonction « foo », il faut commencer par indiquer que nous nous trouvons avant l’appel de la fonction transmise au dé­co­ra­teur dans le paramètre « fonction ». La fonction du paramètre est ensuite exécutée. Un nouvel appel de la fonction « print » de Python est alors effectué ; il indique que nous nous trouvons après l’appel de la fonction en­re­gis­trée en tant que paramètre.

La deuxième partie du code comprend une dé­fi­ni­tion de la fonction appelée « bar », qui reçoit un paramètre de transfert nommé « y ». Il est facile de com­prendre la fonc­tion­na­lité de « bar » : elle affiche à l’écran la phrase « Appel de la fonction bar avec la valeur y », en utilisant pour « y » la valeur transmise en tant que paramètre. La fonction « bar » a pour par­ti­cu­la­rité d’être « décorée ». Vous pouvez le voir dans l’exemple de code, à la ligne « @dec », avant la dé­fi­ni­tion de la fonction.

Mais que se passe-t-il exac­te­ment lorsqu’une fonction a été « décorée » ? Imaginons que nous n’ayons pas spécifié le Python Decorator, à savoir la ligne de code « @dec ». L’appel de la fonction « bar », qui clôt notre exemple de code, donnerait alors le résultat suivant :

Appel de la fonction bar avec la valeur Test
Python

Ici, il se passe exac­te­ment ce qui est prévu pour un appel de fonction : la chaîne Python « Test », transmise pour le paramètre « y », est insérée dans la dé­cla­ra­tion « print ». Le résultat de la fonction reflète donc cette action.

Recréons main­te­nant le résultat du même appel de la fonction « bar », cette dernière étant cette fois « décorée » à l’aide de notre Python Decorator :

Avant l'appel de la fonction bar
Appel de la fonction bar avec la valeur Test
Après l'appel de la fonction bar

Ce que vous voyez alors peut vous sur­prendre : une fois « décorée », notre fonction n’affiche plus seulement à l’écran le résultat de sa propre dé­cla­ra­tion « print ». En réalité, le résultat de notre dé­co­ra­teur de fonction a été « encapsulé », de manière que les deux dé­cla­ra­tions « print » de la fonction auxi­liaire « foo » soient elles aussi prises en con­si­dé­ra­tion. La prin­ci­pale fonc­tion­na­lité de la fonction « bar » a donc été améliorée par l’in­tro­duc­tion de deux résultats « print » sup­plé­men­taires, et ce grâce à l’uti­li­sa­tion du Python Decorator.

Cet exemple reste bien sûr ar­ti­fi­ciel et ne s’inscrit dans aucune logique de pro­gram­ma­tion ap­pro­fon­die. Il devrait toutefois vous aider à mieux com­prendre le fonc­tion­ne­ment des Python De­co­ra­tors. Il va de soi que vous pouvez intégrer la fonc­tion­na­lité Python de votre choix à la fonction « Decorator ».

Python De­co­ra­tors : extraire des con­di­tions ré­cur­rentes

Vous souhaitez peut-être con­di­tion­ner l’exécution de certaines de vos fonctions. Pour ce faire, les dé­cla­ra­tions « if…else » en Python vous sont pro­ba­ble­ment déjà fa­mi­lières. Si ces con­di­tions doivent être vérifiées à dif­fé­rents em­pla­ce­ments, il peut toutefois s’avérer judicieux, pour garantir la li­si­bi­lité de votre code, d’ex­ter­na­li­ser cette condition en faisant appel à un Python Decorator.

L’exemple de code ci-dessous devrait vous permettre de vi­sua­li­ser la manière dont vous pouvez utiliser votre Python Decorator. Quelques opé­ra­teurs ma­thé­ma­tiques ne sont définis que sur les nombres naturels ; un dé­co­ra­teur de fonction chargé de vérifier si le paramètre de transfert d’une fonction cor­res­pond ou non à un nombre naturel pourrait donc vous être utile.

def nombre_naturel(fonction):
 def test(x):
  if type(x) == int and x > 0:
   return fonction(x)
  else:
   raise Exception("L'argument n'est pas un nombre naturel")
@nombre_naturel
def fac(n):
 if n == 1:
  return 1
 else:
  return n * fac(n-1)
print(fac(5))
print(fac(-1))
Python

Dans le code ci-dessus, nous com­men­çons par définir notre Python Decorator appelé « nombre_naturel ». Il permet de vérifier si l’argument de la fonction qui lui a été transmise (« fonction ») cor­res­pond ou non à un nombre naturel. Pour ce faire, la condition « if » vérifie tout d’abord le type de l’argument. Un test est également réalisé pour dé­ter­mi­ner si l’argument est un nombre positif supérieur à 0. Dans l’af­fir­ma­tive, la fonction transmise au dé­co­ra­teur en tant que paramètre est exécutée. Dans le cas contraire, une exception précisant que l’argument de la fonction ne cor­res­pond pas à un nombre naturel est renvoyée.

En pratique, le fonc­tion­ne­ment de notre Python Decorator peut être illustré par l’ob­ser­va­tion de la fonction qu’il « décore », appelée « fac ». Celle-ci est définie dans le code et appelée une première fois avec la valeur « 5 », puis une seconde avec la valeur « -1 ». Le résultat se présente alors comme suit :

120
Traceback (most recent call last):
    File "<pyshell#17>", line 1, in <module>
        fac(-1)
    File "<pyshell#11>", line 6, in test
        raise Exception("L'argument n'est pas un nombre naturel")
Exception: L'argument n'est pas un nombre naturel

Vous voyez tout d’abord le nombre « 120 », qui cor­res­pond à la fac­to­rielle de 5. La fonction fac­to­rielle fonc­tionne donc pour les nombres naturels. L’appel de cette fonction fac­to­rielle avec un nombre négatif entraîne toutefois une erreur… due au Python Decorator ! Un nombre négatif n’étant pas un nombre naturel, la fonction fac­to­rielle ne doit pas être exécutée ici.

Aller au menu principal