Imaginez que vous développez une application Web et que vous devez enregistrer chaque appel d'API, vérifier les droits d'accès des utilisateurs et mesurer le temps d'exécution des fonctions. Vous pouvez, bien sûr, copier le même code dans chaque fonction, mais il existe un moyen plus élégant : les décorateurs. C'est l'un des outils Python les plus puissants qui vous permet de modifier le comportement des fonctions sans modifier leur code source.
Que sont les décorateurs
Un décorateur est une fonction qui prend une autre fonction comme argument et renvoie une nouvelle fonction avec des fonctionnalités étendues. Cela semble compliqué ? En fait, tout est plus simple qu'il n'y paraît.
def my_decorator(func):
def wrapper():
print("Something happens before the function is called")
func()
print("Something happens after calling the function")
return wrapper
@my_decorator
def say_hello():
print("Hi!")
say_hello()Résultat de l'exécution :
Что-то происходит до вызова функции
Привет!
Что-то происходит после вызова функцииLe symbole @ est un sucre syntaxique Python. L'entrée @my_decorator avant la fonction est équivalente à say_hello = my_decorator(say_hello).
Décorateurs avec arguments
Mais que faire si notre fonction accepte des paramètres ? Pour cela, nous utilisons *args et **kwargs :
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def greet(name):
print(f"Hi, {name}!")
greet("Alexey")Conclusion :
Привет, Алексей!
Привет, Алексей!
Привет, Алексей!Ici, nous avons créé un décorateur avec un paramètre qui répète l'appel de la fonction un nombre de fois spécifié.

Exemples pratiques de décorateurs
Mesure du temps d'exécution
import time
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"The {func.__name__} function was executed in {end - start:.4f} seconds")
return result
return wrapper
@timer
def heavy_computation():
time.sleep(2)
return "Done"
heavy_computation()Faites attention à @wraps(func) — c'est un décorateur intégré du module functools, qui enregistre les métadonnées de la fonction d'origine (nom, documentation, etc.).
Mise en cache des résultats
def memoize(func):
cache = {}
@wraps(func)
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoize
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(100)) # S'exécute instantanément grâce à la mise en cacheVérification des droits d'accès
def require_auth(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if not user.get('is_authenticated'):
raise PermissionError("Authorization required")
return func(user, *args, **kwargs)
return wrapper
@require_auth
def delete_account(user, account_id):
print(f"Account {account_id} has been deleted")
user = {'is_authenticated': True, 'username': 'admin'}
delete_account(user, 123)Chaînes de décorateurs
Les décorateurs peuvent être combinés en appliquant plusieurs fonctions à une seule :
@timer
@memoize
def complex_calculation(x, y):
time.sleep(1)
return x ** y
# Le premier appel prendra ~ 1 seconde
complex_calculation(2, 10)
# Le deuxième appel sera instantané (le résultat est mis en cache)
complex_calculation(2, 10)Les décorateurs sont appliqués de bas en haut, c'est-à-dire d'abord memoize, puis timer.
Les classes en tant que décorateurs
Les décorateurs ne doivent pas nécessairement être des fonctions. Vous pouvez utiliser les classes suivantes :
class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"Call #{self.count} of the {self.func.__name__} function"_} ")
return self.func(*args, **kwargs)
@CountCalls
def process_data():
print("Processing data...")
process_data()
process_data()
process_data()
Décorateurs Python intégrés
Python fournit plusieurs décorateurs intégrés utiles :
@property— transforme la méthode en attribut de classe@staticmethod— crée une méthode statique@classmethod— crée une méthode de classe@functools.lru_cache— mise en cache avec limitation de taille@dataclass— création automatique de méthodes de classe
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_function(param):
# Calculs complexes
return param * 2Quand utiliser les décorateurs
Les décorateurs sont idéaux pour les tâches qui doivent être appliquées à de nombreuses fonctions : journalisation, validation des données d'entrée, gestion des exceptions, contrôle d'accès, mise en cache, mesure des performances, logique de nouvelle tentative en cas d'erreurs réseau. Ils aident à respecter le principe DRY (Don't Repeat Yourself) et rendent le code plus propre et plus clair.
Problèmes potentiels
Malgré toute la puissance des décorateurs, il faut se souvenir de quelques points. L'utilisation excessive de décorateurs peut rendre le débogage du code plus difficile. Les décorateurs ajoutent de petits frais généraux aux performances. Il est important de toujours utiliser @wraps pour enregistrer les métadonnées de la fonction. Les chaînes de plusieurs décorateurs peuvent réduire la lisibilité du code.
Résumé
Les décorateurs sont un moyen élégant de modifier et d'étendre les fonctionnalités du code sans le modifier. Ils sont largement utilisés dans des frameworks populaires tels que Flask et Django, et comprendre leur fonctionnement vous simplifiera considérablement la vie en tant que développeur. Commencez par des décorateurs simples pour la journalisation ou la mesure du temps, et vous découvrirez progressivement de plus en plus de situations où ils seront utiles.
Vous souhaitez maîtriser les décorateurs et autres fonctionnalités avancées de Python en pratique ?
Annexe Code a été créé spécialement pour que vous puissiez apprendre la programmation à un rythme confortable, avec des explications claires en russe et des exemples pratiques réels. Nous analysons des sujets complexes dans un langage simple, des bases aux techniques professionnelles. Chaque leçon est conçue pour que vous ne vous contentiez pas de mémoriser la syntaxe, mais que vous compreniez comment appliquer vos connaissances à des projets réels.
Et si vous avez des questions pendant la formation, bienvenue dans notre Chaîne Telegram! C'est une communauté vivante de développeurs où vous pouvez poser n'importe quelle question et obtenir une réponse détaillée. Notre atmosphère est amicale et instructive : chaque jour, nous analysons les meilleurs sujets en développement, partageons nos expériences et nous aidons mutuellement à grandir. Rejoignez Kodik : commencez votre parcours de programmation avec ceux qui savent vraiment comment rendre l'apprentissage efficace et intéressant !
