DĂ©corateurs Python đ : fonctions amĂ©liorĂ©es
Décorateurs Python : fonctions améliorées
Section titled âDĂ©corateurs Python : fonctions amĂ©liorĂ©esâIntroduction
Section titled âIntroductionâ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).
Théorie sur les fonctions en Python
Section titled âThĂ©orie sur les fonctions en PythonâFonctions comme objets de premiĂšre classe
Section titled âFonctions comme objets de premiĂšre classeâ- DĂ©finition: Les fonctions peuvent ĂȘtre stockĂ©es, passĂ©es en argument, et retournĂ©es.
def dire_bonjour(): print("Bonjour !")
salutation = dire_bonjour # aliassalutation()Fonctions passées en argument
Section titled âFonctions passĂ©es en argumentâdef executer_fonction(func): print("On exĂ©cute...") func()
executer_fonction(dire_bonjour)Fonctions retournées (closures)
Section titled âFonctions retournĂ©es (closures)âdef faire_salut(): def message(): print("Salut !") return message
fonction_retournee = faire_salut()fonction_retournee()Les décorateurs
Section titled âLes dĂ©corateursâStructure dâun dĂ©corateur
Section titled âStructure dâun dĂ©corateurâdef mon_decorateur(func): def wrapper(): print("Avant") func() print("AprĂšs") return wrapperApplication avec la syntaxe @
Section titled âApplication avec la syntaxe @â@mon_decorateurdef dire_bonjour(): print("Bonjour tout le monde !")
dire_bonjour()Décorateurs avec arguments
Section titled âDĂ©corateurs avec argumentsâdef mon_decorateur(func): def wrapper(*args, **kwargs): print("Avant") result = func(*args, **kwargs) print("AprĂšs") return result return wrapper
@mon_decorateurdef 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_executiondef addition(a, b): """Additionne deux nombres.""" return a + b
print(addition.__name__) # additionprint(addition.__doc__) # Additionne deux nombres.Exemples du monde réel
Section titled âExemples du monde rĂ©elâMesurer le temps dâexĂ©cution
Section titled âMesurer le temps dâexĂ©cutionâimport timeimport 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
@chronometredef traitement_lourd(): time.sleep(2) print("Traitement terminé !")
traitement_lourd()Vérifier des permissions (méthodes de classe)
Section titled âVĂ©rifier des permissions (mĂ©thodes de classe)â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.")Décorateurs intégrés pour les classes
Section titled âDĂ©corateurs intĂ©grĂ©s pour les classesâ- @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_nomEmpiler 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_Bdef action(): print("Action")
action()# Ordre: A avant -> B avant -> Action -> B aprĂšs -> A aprĂšsBonnes pratiques
Section titled âBonnes pratiquesâ- Args gĂ©nĂ©riques: Utiliser
*argset**kwargspour ne pas brider les signatures. - wraps: Utiliser
functools.wrapspour 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.
Ăvaluation des connaissances
Section titled âĂvaluation des connaissancesâExercices pratiques
Section titled âExercices pratiquesâ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_simpledef 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_executiondef 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
@chronometredef 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_positifdef 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@Bdef cible(): """Fonction cible démonstration.""" print("Exécution de cible")
cible()print(cible.__name__) # cibleprint(cible.__doc__) # Fonction cible démonstration.Conclusion
Section titled âConclusionâ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.
đą Partagez cet article
Section titled âđą Partagez cet articleâDerniĂšre mise Ă jour : 03 DĂ©cembre 2025