ProgrammationDéveloppeur Backend

Expliquez comment fonctionnent les décorateurs en Python. Quelle est leur principale utilité, comment sont-ils implémentés, et quelles subtilités peuvent survenir lors de leur utilisation ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

Les décorateurs sont des fonctions qui prennent une autre fonction et renvoient une nouvelle fonction avec un comportement étendu ou modifié. Ils sont souvent utilisés pour le journalisation, la vérification des droits, le caching, la mesure du temps d'exécution, etc.

Les décorateurs sont implémentés à l'aide de fermetures (closure) ou de classes implémentant la méthode __call__. La syntaxe classique :

# Décorateur simple def simple_decorator(func): def wrapper(*args, **kwargs): print("Avant d'appeler la fonction") result = func(*args, **kwargs) print("Après avoir appelé la fonction") return result return wrapper @simple_decorator def my_func(): print("Fonction principale") my_func()

Le résultat sera :

Avant d'appeler la fonction
Fonction principale
Après avoir appelé la fonction

Principale utilité — encapsulation de la logique répétitive en dehors de la logique métier principale.

Subtilités :

  • Sans utiliser functools.wraps, le nom de la fonction d'origine et son docstring sont perdus.
  • Si le décorateur prend des arguments, une triple profondeur de fonctions est nécessaire.

Question piégée

Question : "Si je décore une fonction avec un décorateur, puis que j'essaie d'obtenir le nom de la fonction via __name__, que vais-je voir et comment conserver le nom d'origine ?"

Réponse :

Par défaut, le nom changera pour le nom de l'enveloppe (généralement wrapper). Pour conserver les métadonnées d'origine, utilisez functools.wraps :

import functools def dec(f): @functools.wraps(f) def wrapper(*args): return f(*args) return wrapper @dec def foo(): pass print(foo.__name__) # affichera 'foo', pas 'wrapper'

Exemples d'erreurs réelles dues à une méconnaissance des subtilités du sujet


Histoire

Dans une grande automatisation des ressources, après avoir enveloppé des fonctions avec des décorateurs, le système de tests automatisés s'appuyant sur la réflexion des noms des fonctions de test a cessé de fonctionner. Le problème était l'absence de functools.wraps.


Histoire

Un décorateur ajoutant des journaux ne supportait pas les fonctions avec des signatures différentes, car *args, **kwargs n'étaient pas utilisés. Certaines fonctions étaient simplement cassées (échec silencieux).


Histoire

Dans un projet avec une authentification via REST API, le développeur a implémenté un décorateur avec des paramètres mais a oublié de correctement imbriquer les fonctions (il y avait une imbrication à deux niveaux au lieu de trois). En conséquence, le décorateur ne pouvait pas accepter de paramètres.