Guide des décorateurs Python pour les programmeurs avancés
Les décorateurs Python sont un outil puissant et flexible permettant de modifier le comportement des fonctions ou des méthodes. Ils permettent aux programmeurs d'étendre ou de modifier les fonctionnalités des objets appelables de manière claire, lisible et maintenable. Cet article explore les concepts avancés liés aux décorateurs Python, notamment les décorateurs imbriqués, les arguments de décorateur et les décorateurs basés sur les classes.
Que sont les décorateurs ?
Les décorateurs sont des fonctions qui modifient le comportement d'une autre fonction. Ils encapsulent une autre fonction pour étendre son comportement sans modifier explicitement son code. Les décorateurs sont définis à l'aide de la syntaxe @decorator_name
et sont placés au-dessus de la définition de la fonction.
Syntaxe de base du décorateur
Un décorateur simple prend une fonction comme argument, définit une fonction interne qui ajoute un comportement, puis renvoie la fonction interne.
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Fonctions de décoration avec arguments
Les décorateurs peuvent être plus flexibles en acceptant des arguments. Pour créer un tel décorateur, vous devez écrire une fonction qui renvoie un décorateur. Cela permet d'ajouter un comportement plus dynamique aux décorateurs.
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
Décorateurs imbriqués
Les décorateurs peuvent être imbriqués pour combiner plusieurs comportements. Par exemple, nous pouvons utiliser deux ou plusieurs décorateurs sur une seule fonction.
def uppercase_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def repeat_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result + result
return wrapper
@repeat_decorator
@uppercase_decorator
def say_word(word):
return word
print(say_word("hello"))
Décorateurs basés sur les classes
En Python, les décorateurs peuvent également être implémentés en tant que classes à l'aide de la méthode __call__
. Les décorateurs basés sur des classes sont utiles lorsque vous avez besoin d'une gestion d'état et d'un comportement plus complexes.
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"Call {self.num_calls} of {self.func.__name__!r}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello()
say_hello()
Utilisation de functools.wraps
pour préserver les métadonnées
Lorsque vous écrivez des décorateurs, la fonction décorée perd ses métadonnées d'origine, telles que son nom et sa docstring. Le décorateur functools.wraps
peut être utilisé pour copier les métadonnées de la fonction d'origine dans la fonction wrapper.
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Wrapper function executed before", func.__name__)
return func(*args, **kwargs)
return wrapper
@my_decorator
def display_info(name, age):
"""Displays name and age."""
print(f"display_info ran with arguments ({name}, {age})")
print(display_info.__name__) # Output: display_info
print(display_info.__doc__) # Output: Displays name and age.
Conclusion
Les décorateurs Python sont une fonctionnalité puissante qui permet une conception de code flexible et une modification du comportement. Une utilisation avancée, comme les décorateurs imbriqués, les décorateurs avec arguments et les décorateurs basés sur les classes, peut fournir encore plus de fonctionnalités et de lisibilité aux programmes Python. En comprenant et en utilisant correctement les décorateurs, les développeurs peuvent écrire du code plus concis, efficace et lisible.