Décorateurs Python

Un décorateur est une fonctionnalité avancée de Python utilisée pourétendre dynamiquement les fonctionnalités de fonctions ou de classes sans modifier le code d'origine de la fonction。

Essentiellement, un décorateur est une fonction : il reçoit une fonction comme argument et renvoie une nouvelle fonction (généralement une version améliorée de la fonction d'origine).

Les décorateurs sont appliqués à l'aide de la syntaxe@decorator_nameplacée avant la définition d'une fonction ou d'une méthode.

Python fournit également quelques décorateurs intégrés, tels que@staticmethodet@classmethod。

Cas d'utilisation courants :

  • Journalisation :Enregistrer les informations d'appel de fonction, les paramètres et les valeurs de retour
  • Statistiques de performance :Mesurer le temps d'exécution d'une fonction
  • Contrôle d'accès :Restreindre les autorisations d'accès aux fonctions
  • Mise en cache :Mettre en cache les résultats de fonctions pour améliorer les performances

Syntaxe de base

L'idée centrale d'un décorateur est :utiliser une fonction pour "envelopper" une autre fonction。

Syntaxe

def decorator_function(original_function):
    def wrapper(*args, **kwargs):
        # Avant l'appel
        print("Avant l'exécution")

        result = original_function(*args, **kwargs)

        # Après l'appel
        print("Après l'exécution")

        return result
    return wrapper

@decorator_function
def target_function():
    print("Exécution de la fonction originale")

Explication :

  • decorator_function: fonction décoratrice (reçoit la fonction originale)
  • wrapper: fonction d'encapsulation (réellement exécutée)
  • @decorator_function: équivalent à un remplacement de fonction

Forme équivalente :

target_function = decorator_function(target_function)

👉 Lors de l'appeltarget_function(), ce qui est réellement exécuté estwrapper()


Utilisation des décorateurs

Les décorateurs sont appliqués à l'aide du@sucre syntaxique placé avant la définition de la fonction :

@time_logger
def target_function():
    pass

Équivalent à :

def target_function():
    pass

target_function = time_logger(target_function)

Ce mécanisme nous permet d'ajouter uniformément des fonctionnalités (telles que la journalisation, les autorisations, etc.) sans modifier la fonction d'origine.


Exemple : affichage des journaux

def my_decorator(func):
    def wrapper():
        print("Avant l'exécution de la fonction")
        func()
        print("Après l'exécution de la fonction")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

Sortie :

函数执行前
Hello!
函数执行后
  • my_decoratorReçoitsay_hello
  • @my_decoratorRemplace la fonction d'origine

Décorateurs avec paramètres

Si la fonction d'origine a des paramètres, vous devez, dans lewrapperuse*args, **kwargs:

Exemple

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Avant l'exécution")
        func(*args, **kwargs)
        print("Après l'exécution")
    return wrapper

@my_decorator
def greet(name):
    print(f"Bonjour, {name}!")

greet("Alice")

Sortie :

执行前
Hello, Alice!
执行后

Explication :Utilisation*args, **kwargspeut accepter des fonctions avec un nombre quelconque de paramètres.


Décorateurs avec paramètres (avancé)

def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def say_hello():
    print("Hello!")

say_hello()

Explication :Il s'agit d'une "fabrique de décorateurs" ; la fonction externe est utilisée pour recevoir des paramètres.

Hello!
Hello!
Hello!


Décorateurs de classe

En plus des fonctions, les décorateurs peuvent également être appliqués aux classes.

Un décorateur de classe reçoit une classe et renvoie une classe modifiée ou une classe enveloppe.

  • Améliorer les méthodes de classe
  • Contrôler le processus d'instanciation
  • Implémenter des fonctionnalités telles que les singletons et la journalisation

Décorateurs de classe basés sur des fonctions

Exemple

def log_class(cls):
    class Wrapper:
        def __init__(self, *args, **kwargs):
            self.wrapped = cls(*args, **kwargs)

        def __getattr__(self, name):
            return getattr(self.wrapped, name)

        def display(self):
            print("Avant l'appel")
            self.wrapped.display()
            print("Après l'appel")

    return Wrapper

@log_class
class MyClass:
    def display(self):
        print("Méthode originale")

obj = MyClass()
obj.display()
Before call
Original method
After call

Décorateurs de classe basés sur des classes

Exemple : patron Singleton

class SingletonDecorator:
    def __init__(self, cls):
        self.cls = cls
        self.instance = None

    def __call__(self, *args, **kwargs):
        if self.instance is None:
            self.instance = self.cls(*args, **kwargs)
        return self.instance

@SingletonDecorator
class Database:
    def __init__(self):
        print("Initialisation")

db1 = Base de données()
db2 = Base de données()
print(db1 is db2)
初始化
True

Décorateurs intégrés

Décorateurs intégrés couramment utilisés :

  1. @staticmethod: définit une méthode statique
  2. @classmethod: définit une méthode de classe
  3. @property: transforme une méthode en propriété

Exemple

class MyClass:
    @staticmethod
    def static_method():
        print("Méthode statique")

    @classmethod
    def class_method(cls):
        print(cls.__name__)

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

Superposition de plusieurs décorateurs

Plusieurs décorateursenveloppent la fonction du bas vers le haut pendant la phase de définition,et s'exécutent du haut vers le bas pendant la phase d'appel:

Exemple

def decorator1(func):
    def wrapper():
        print("Décorateur 1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("Décorateur 2")
        func()
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("Hello!")

say_hello()

Sortie finale :

Decorator 1
Decorator 2
Hello!

Résumé essentiel

Decorator = a function that wraps a function + extending functionality without modifying the original code
  • La syntaxe @ est essentiellement un remplacement de fonction
  • wrapper est la fonction qui est réellement exécutée
  • Il est recommandé d'utiliser *args, **kwargs pour une plus grande polyvalence
  • Prend en charge les fonctions, les classes et même les décorateurs avec paramètres
Autres extensions