Skip to content

DĂ©corateurs Python 🐍 : fonctions amĂ©liorĂ©es

Les dĂ©corateurs en Python permettent d’enrichir ou modifier le comportement d’une fonction sans changer son code. Dans le monde rĂ©el, ils servent Ă :

  • Logs: Tracer les appels et les erreurs.
  • Permissions: VĂ©rifier l’accĂšs avant d’exĂ©cuter une action.
  • Performance: Mesurer le temps d’exĂ©cution et profiler.
  • API/CLI: Ajouter des validations et du routage (ex. Click, FastAPI).

  • DĂ©finition: Les fonctions peuvent ĂȘtre stockĂ©es, passĂ©es en argument, et retournĂ©es.
def dire_bonjour():
print("Bonjour !")
salutation = dire_bonjour # alias
salutation()
def executer_fonction(func):
print("On exécute...")
func()
executer_fonction(dire_bonjour)
def faire_salut():
def message():
print("Salut !")
return message
fonction_retournee = faire_salut()
fonction_retournee()

def mon_decorateur(func):
def wrapper():
print("Avant")
func()
print("AprĂšs")
return wrapper
@mon_decorateur
def dire_bonjour():
print("Bonjour tout le monde !")
dire_bonjour()
def mon_decorateur(func):
def wrapper(*args, **kwargs):
print("Avant")
result = func(*args, **kwargs)
print("AprĂšs")
return result
return wrapper
@mon_decorateur
def dire_bonjour_avec_nom(nom):
print(f"Bonjour, {nom} !")
dire_bonjour_avec_nom("Alice")

Préserver le nom et la docstring avec functools.wraps

Section titled “PrĂ©server le nom et la docstring avec functools.wraps”
import functools
def log_execution(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Appel: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_execution
def addition(a, b):
"""Additionne deux nombres."""
return a + b
print(addition.__name__) # addition
print(addition.__doc__) # Additionne deux nombres.

import time
import functools
def chronometre(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"Durée: {end - start:.4f}s")
return result
return wrapper
@chronometre
def traitement_lourd():
time.sleep(2)
print("Traitement terminé !")
traitement_lourd()
import functools
def verifier_permissions(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
if not self.est_admin:
print("AccÚs refusé.")
return
return func(self, *args, **kwargs)
return wrapper
class Systeme:
def __init__(self, est_admin):
self.est_admin = est_admin
@verifier_permissions
def supprimer_donnees(self):
print("Données supprimées.")
  • @staticmethod: MĂ©thode indĂ©pendante de l’instance.
  • @classmethod: MĂ©thode liĂ©e Ă  la classe (premier paramĂštre: cls).
  • @property: Getter/Setter Pythonique.
class Personne:
def __init__(self, nom):
self._nom = nom
@property
def nom(self):
return self._nom
@nom.setter
def nom(self, nouveau_nom):
if not nouveau_nom:
raise ValueError("Le nom ne peut pas ĂȘtre vide.")
self._nom = nouveau_nom

Empiler des dĂ©corateurs (ordre d’exĂ©cution)

Section titled “Empiler des dĂ©corateurs (ordre d’exĂ©cution)”
def deco_A(func):
def wrapper(*args, **kwargs):
print("A avant")
result = func(*args, **kwargs)
print("A aprĂšs")
return result
return wrapper
def deco_B(func):
def wrapper(*args, **kwargs):
print("B avant")
result = func(*args, **kwargs)
print("B aprĂšs")
return result
return wrapper
@deco_A
@deco_B
def action():
print("Action")
action()
# Ordre: A avant -> B avant -> Action -> B aprĂšs -> A aprĂšs

  • Args gĂ©nĂ©riques: Utiliser *args et **kwargs pour ne pas brider les signatures.
  • wraps: Utiliser functools.wraps pour prĂ©server nom, docstring et attributs.
  • LisibilitĂ©: Limiter l’empilement de dĂ©corateurs pour Ă©viter la complexitĂ©.
  • ResponsabilitĂ©: Un dĂ©corateur = une responsabilitĂ© claire (SRP).
  • Erreurs: Lever des exceptions explicites et journaliser les erreurs.


Exercice 1 : Décorateur simple

ÉnoncĂ©: CrĂ©ez un dĂ©corateur qui affiche “DĂ©but” avant et “Fin” aprĂšs l’exĂ©cution d’une fonction.

Solution:

def decorateur_simple(func):
def wrapper(*args, **kwargs):
print("Début")
result = func(*args, **kwargs)
print("Fin")
return result
return wrapper
@decorateur_simple
def dire_hello():
print("Hello !")
dire_hello()

Exercice 2 : Décorateur de logging

ÉnoncĂ©: Journalisez le nom de la fonction et ses arguments avant l’exĂ©cution.

Solution:

def log_execution(func):
def wrapper(*args, **kwargs):
print(f"Appel de {func.__name__} avec {args} et {kwargs}")
return func(*args, **kwargs)
return wrapper
@log_execution
def addition(a, b):
return a + b
print(addition(3, 5))

Exercice 3 : Chronométrage

ÉnoncĂ©: Mesurez le temps d’exĂ©cution d’une fonction.

Solution:

import time
def chronometre(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"Durée: {end - start:.4f}s")
return result
return wrapper
@chronometre
def calcul():
time.sleep(1)
print("Calcul terminé")
calcul()

Exercice 4 : VĂ©rification d’arguments

ÉnoncĂ©: VĂ©rifiez qu’un argument est positif avant d’exĂ©cuter la fonction.

Solution:

def verifier_positif(func):
def wrapper(x):
if x < 0:
print("Erreur: valeur négative interdite.")
return
return func(x)
return wrapper
@verifier_positif
def racine_carree(x):
print(x ** 0.5)
racine_carree(9)
racine_carree(-4)

Exercice 5 : Empilement de décorateurs avec wraps

ÉnoncĂ©: CrĂ©ez deux dĂ©corateurs (A, B) empilĂ©s et montrez l’ordre d’exĂ©cution. PrĂ©servez les mĂ©tadonnĂ©es avec functools.wraps.

Solution:

import functools
def A(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("A avant")
result = func(*args, **kwargs)
print("A aprĂšs")
return result
return wrapper
def B(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("B avant")
result = func(*args, **kwargs)
print("B aprĂšs")
return result
return wrapper
@A
@B
def cible():
"""Fonction cible démonstration."""
print("Exécution de cible")
cible()
print(cible.__name__) # cible
print(cible.__doc__) # Fonction cible démonstration.

Les décorateurs sont un outil puissant pour factoriser des comportements transverses (logs, sécurité, performance) sans polluer le code métier. En maßtrisant les bases (fonctions comme objets), la structure des wrappers, functools.wraps, et les usages du monde réel, vous écrivez un code plus propre, testable et maintenable.



À propos de l'auteur

Riyad ODJOUADEExpert en cybersécurité & infrastructure

Je partage des guides techniques pratiques sur la cybersécurité, l'administration systÚme et le développement web. Tous les contenus sont basés sur des expérimentations réelles.

DerniÚre mise à jour : 03 Décembre 2025