Side-by-Side Language Deep Dive

Décorateurs Python et modèle de conception de décorateur : les principales différences

Comparez les décorateurs Python et le modèle de conception de décorateur classique. Comprenez les différences entre l'encapsulation de fonctions au moment de la définition et la composition d'objets dynamiques d'exécution avec du code exécutable.

Bien que les décorateurs Python et le modèle de conception du décorateur partagent le même nom et le concept général de « enveloppement » du code pour étendre le comportement, ils représentent des constructions et des philosophies complètement différentes en matière de programmation.

Un décorateur Python est une fonctionnalité du langage, un sucre syntaxique qui vous permet d'encapsuler une fonction, une méthode ou une classe au moment de la définition. Il s'agit d'une forme de métaprogrammation qui s'exécute lorsque le module est importé ou défini, modifiant ainsi le comportement de cette fonction pour le reste de l'exécution de l'application.

Le modèle de conception Decorator, initialement défini par le Gang of Four (GoF), est un modèle de conception structurelle orienté objet. Il est conçu pour ajouter des responsabilités à des objets individuels de manière dynamique au moment de l'exécution, sans affecter les autres objets de la même classe, en utilisant des classes wrapper et une composition dynamique.

Matrice de comparaison des fonctionnalités

FeaturePythonOther Language
Concept de baseSucre syntaxique au niveau du langage pour encapsuler les fonctions/classes.Modèle de conception pour ajouter dynamiquement un comportement à des objets individuels.
Temps d'exécutionTemps de définition (s'exécute une fois lorsque le module est chargé).Runtime (instancié dynamiquement lors de l'exécution du programme).
Entité cibleFonctions, méthodes ou classes entières (portée statique).Instances d'objet spécifiques (portée dynamique).
Méthode de mise en œuvreFermetures et fonctions d'assistance utilisant la syntaxe `@decorator`.Héritage de classe, alignement d'interface et composition d'objets.

Syntax & Idiom Comparisons

01.Décorateur Python : Wrapper de fonctions (temps de définition)

Les décorateurs Python profitent de fonctions de première classe pour intercepter les appels. Lorsque vous écrivez `@my_decorator`, Python transmet la fonction décorée à votre fonction décorateur et lie la fonction wrapper renvoyée au nom de la fonction d'origine.

Dans cet exemple, le décorateur `@log_call` encapsule une fonction simple pour suivre quand elle est exécutée et ce qu'elle renvoie. Notez que cet emballage est gravé dans le marbre au moment où la fonction est définie.

def log_call(func):
    def wrapper(*args, **kwargs):
        print(f"[LOG] Executing '{func.__name__}' with args {args}")
        result = func(*args, **kwargs)
        print(f"[LOG] '{func.__name__}' returned: {result}")
        return result
    return wrapper

@log_call
def add(a, b):
    return a + b

# The wrapping occurs once at definition time
print("Result of add(5, 7):", add(5, 7))
python
// Decorators in Python are syntactic sugar for function wrappers:
// add = log_call(add)
// They exist primarily to avoid duplicate boilerplate for logging, timing, and auth.

02.Modèle de conception de décorateur : enveloppement d'objet (composition d'exécution)

Le modèle de conception classique du décorateur utilise la composition des classes. Vous disposez d'une classe de composant de base et de classes de décorateurs qui enveloppent ce composant de base. Au moment de l'exécution, vous enchaînez ces constructeurs pour créer dynamiquement un objet personnalisé.

Ici, nous implémentons un système de décoration de café classique. Nous pouvons envelopper un objet Coffee de base dans un MilkDecorator et l'envelopper dans un SugarDecorator, en calculant le coût final de manière dynamique au moment de l'exécution.

class Coffee:
    def get_cost(self):
        return 5.0
    def get_description(self):
        return "Simple Coffee"

class MilkDecorator:
    def __init__(self, coffee):
        self.coffee = coffee
    def get_cost(self):
        return self.coffee.get_cost() + 1.5
    def get_description(self):
        return self.coffee.get_description() + ", Milk"

class SugarDecorator:
    def __init__(self, coffee):
        self.coffee = coffee
    def get_cost(self):
        return self.coffee.get_cost() + 0.5
    def get_description(self):
        return self.coffee.get_description() + ", Sugar"

# Chaining wrappers dynamically at runtime
my_drink = Coffee()
my_drink = MilkDecorator(my_drink)
my_drink = SugarDecorator(my_drink)

print("Drink description:", my_drink.get_description())
print("Total Cost: $", my_drink.get_cost())
python
// Standard OO languages (like Java) require shared interfaces:
// interface Coffee { double getCost(); }
// class SimpleCoffee implements Coffee { ... }
// class MilkDecorator implements Coffee { ... }
// Python's duck typing allows dynamic composition without interfaces.

Verdict et résumé

Utilisez les décorateurs Python (@decorator) lorsque vous souhaitez appliquer des préoccupations transversales (telles que la journalisation, la synchronisation, l'authentification, la mise en cache ou la validation des entrées) aux fonctions ou aux itinéraires de manière uniforme dans votre application.

Utilisez le modèle de conception Decorator lorsque vous devez attacher ou détacher des comportements d'instances d'objet individuelles de manière dynamique au moment de l'exécution, en particulier lorsque vous combinez plusieurs classes wrapper facultatives dans des séquences arbitraires.

Foire aux questions

Pourquoi la page Wikipédia indique-t-elle que les décorateurs Python ne sont pas le modèle de décorateur ?

Parce que les décorateurs Python standard encapsulent les fonctions et les définitions de classe au moment de la compilation/définition, affectant toutes les instances de cette fonction. Le modèle de conception classique encapsule dynamiquement les instances d’objet individuelles au moment de l’exécution.

Le modèle GoF Decorator est-il utile en Python ?

Oui, mais le typage canard de Python le rend beaucoup plus simple à implémenter que dans les langages typés statiquement comme Java ou C++, puisque les décorateurs n'ont pas besoin d'hériter d'une interface de base formelle.

Autres comparaisons

Ressources Python recommandées

Développez vos connaissances avec des didacticiels interactifs, des aide-mémoire et des comparaisons de codes associés.