Fonctionnement des Décorateurs en Python

Les décorateurs en Python permettent d'étendre le comportement d'une fonction ou d'une méthode sans modifire son code source. Ils sont utiles pour ajouter des opérations préalables ou postérieures, comme mesurer le temps d'exécution ou journaliser les appels.

Concept fondamental

Un décorateur est essentiellement une fonction qui prend une autre fonction en entrée, exécute des actions supplémentaires, puis retourne la fonction modifiée ou une nouvelle fonction. Pour mieux comprendre, considérons une analogie : imaginez un appareil comme un ventilateur. En Python, cet appareil est un objet avec une fonctionnalité de base.

def generer_flux():
    return "flux d'air"

Lorsque nous invoquons generer_flux(), nous activons la fonction pour obtenir le résultat. Sans les parenthèses, nous obtenons l'objet fonction lui-même, qui peut être stocké dans une varible et utilisé ultérieurement.

def generer_flux():
    return "flux d'air"

reference_fonction = generer_flux
print(reference_fonction)
# Sortie : <function at="" generer_flux="">
</function>

Cette propriété permet de manipuler les fonctions comme des objets. Par exemple, une fonction peut accepter une autre fonction comme paramètre.

def enveloppe(fonction_cible):
    return fonction_cible

print(enveloppe(generer_flux))
# Sortie identique à generer_flux

Implémentation d'un décorateur simple

Pour ajouter des actions autour de la fonction originale, nous pouvons imbriquer une fonction interne. Cela évite de modifier l'appel initial.

def enveloppe(fonction_cible):
    def interne():
        print("Début de l'exécution")
        fonction_cible()
        print("Fin de l'exécution")
    return interne

def generer_flux():
    print("flux d'air")

generer_flux = enveloppe(generer_flux)
generer_flux()
# Sortie : Début de l'exécution, flux d'air, Fin de l'exécution

Python offre une syntaxe simplifiée avec le symbole @ pour appliquer un décorateur directement lors de la définition d'une fonction.

def enveloppe(fonction_cible):
    def interne():
        print("Début de l'exécution")
        fonction_cible()
        print("Fin de l'exécution")
    return interne

@enveloppe
def generer_flux():
    print("flux d'air")

generer_flux()
# Même résultat que précédemment

Gestion des paramètres

Pour rendre un décorateur compatible avec des fonctions ayant des arguments, nous uitlisons *args et **kwargs pour capturer tous les paramètres possibles.

def enveloppe(fonction_cible):
    def interne(*args, **kwargs):
        print("Appel avec arguments :", args, kwargs)
        resultat = fonction_cible(*args, **kwargs)
        print("Exécution terminée")
        return resultat
    return interne

@enveloppe
def afficher_message(texte):
    print(texte)

afficher_message("Bonjour")
# Sortie : Appel avec arguments : ('Bonjour',) {}, Bonjour, Exécution terminée

Étiquettes: Python décorateurs fonctions Programmation orientée objet

Publié le 20 juillet à 20h52