Décorateurs Python : fonctionnement, utilité et exemples concrets

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Que sont les décorateurs en Python

Si vous avez codé en Python plus d'une semaine, vous avez forcément vu le symbole @ devant une fonction. C'est un décorateur — un outil de programmation puissant et élégant.

Les décorateurs en Python permettent d'« envelopper » une fonction dans une autre. Ils modifient ou étendent le comportement d'une fonction sans toucher à son code source. Les décorateurs sont omniprésents : dans Flask, Django, FastAPI, pytest, et même dans la bibliothèque standard de Python.

Fonctionnement des décorateurs

Les bases des décorateurs

Un décorateur est une fonction qui prend une autre fonction en argument et retourne une nouvelle fonction (ou la fonction modifiée).

def decorateur(func):
    def wrapper():
        print("Avant l'appel")
        func()
        print("Après l'appel")
    return wrapper

@decorateur
def dire_bonjour():
    print("Bonjour !")

dire_bonjour()

Résultat de l'exécution :

Avant l'appel
Bonjour !
Après l'appel

Le symbole @decorateur est un sucre syntaxique équivalent à :

dire_bonjour = decorateur(dire_bonjour)

Mécanisme interne des décorateurs

Pour bien comprendre les décorateurs en Python, il faut connaître ces concepts clés :

  • En Python, les fonctions sont des objets de première classe
  • Les fonctions peuvent être passées comme arguments à d'autres fonctions
  • On peut définir des fonctions à l'intérieur d'autres fonctions
  • Le mécanisme de fermeture (closure) est essentiel

Modèle universel de décorateur

Voici le modèle minimal d'un décorateur :

def decorateur(func):
    def wrapper(*args, **kwargs):
        # Actions avant l'exécution de la fonction
        resultat = func(*args, **kwargs)
        # Actions après l'exécution de la fonction
        return resultat
    return wrapper

Exemples pratiques de décorateurs

Décorateur de mesure du temps d'exécution

import time

def chronometre(func):
    def wrapper(*args, **kwargs):
        debut = time.time()
        resultat = func(*args, **kwargs)
        duree = time.time() - debut
        print(f"{func.__name__} a pris {duree:.4f} sec")
        return resultat
    return wrapper

@chronometre
def fonction_lente():
    time.sleep(1)
    return "Opération terminée"

fonction_lente()

Ce décorateur est utile pour profiler les performances des fonctions et optimiser votre code.

Décorateur de vérification d'autorisation

def require_admin(func):
    def wrapper(utilisateur, *args, **kwargs):
        if utilisateur != "admin":
            raise PermissionError("Accès refusé")
        return func(utilisateur, *args, **kwargs)
    return wrapper

@require_admin
def supprimer_base(utilisateur):
    print("Base de données supprimée !")
    return True

supprimer_base("admin")  # Exécution réussie

Ce décorateur renforce la sécurité de votre application en contrôlant l'accès aux fonctions critiques.

Décorateur de journalisation

import logging
from functools import wraps

def journaliser_appels(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        logging.info(f"Appel de la fonction {func.__name__} avec arguments {args}, {kwargs}")
        try:
            resultat = func(*args, **kwargs)
            logging.info(f"Fonction {func.__name__} exécutée avec succès")
            return resultat
        except Exception as e:
            logging.error(f"Erreur dans la fonction {func.__name__} : {e}")
            raise
    return wrapper

Décorateurs avec arguments

Création d'une fabrique de décorateurs

Lorsqu'un décorateur doit accepter des paramètres, on crée une fabrique de décorateurs :

def repeter(n):
    def decorateur(func):
        def wrapper(*args, **kwargs):
            resultats = []                

Blogs

Book Recommendations