Techniques et cas d'utilisation avancés des décorateurs
Comme vous l'avez vu, les décorateurs sont un outil puissant pour modifier le comportement des fonctions en Python. Dans cette section, nous explorerons quelques techniques et cas d'utilisation avancés des décorateurs.
Décorer des classes
Les décorateurs peuvent également être utilisés pour modifier le comportement des classes. Voici un exemple d'un décorateur qui ajoute une méthode de journalisation à une classe :
def log_class_methods(cls):
class LoggedClass(cls):
def __getattribute__(self, attr):
if callable(super(LoggedClass, self).__getattribute__(attr)):
def logged_method(*args, **kwargs):
print(f"Calling method {attr}")
return super(LoggedClass, self).__getattribute__(attr)(*args, **kwargs)
return logged_method
return super(LoggedClass, self).__getattribute__(attr)
return LoggedClass
@log_class_methods
class MyClass:
def __init__(self, value):
self.value = value
def do_something(self):
print(f"Doing something with value: {self.value}")
obj = MyClass(42)
obj.do_something() ## Output: Calling method do_something
## Doing something with value: 42
Dans cet exemple, le décorateur log_class_methods
prend une classe en argument et retourne une nouvelle classe qui enveloppe toutes les méthodes de la classe d'origine avec une fonction de journalisation.
Décorateurs avec état
Les décorateurs peuvent également maintenir un état entre les appels de fonction. Cela peut être utile pour la mise en cache, la limitation de débit ou d'autres opérations avec état. Voici un exemple d'un décorateur qui met en cache les résultats d'une fonction :
def cache(func):
cache = {}
def wrapper(*args):
if args in cache:
print("Returning cached result")
return cache[args]
else:
result = func(*args)
cache[args] = result
return result
return wrapper
@cache
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) ## Output: Calculating fibonacci(10)
## 55
print(fibonacci(10)) ## Output: Returning cached result
## 55
Dans cet exemple, le décorateur cache
maintient un dictionnaire des arguments d'appel de fonction et de leurs résultats correspondants. Lorsque la fonction décorée est appelée, le décorateur vérifie d'abord si le résultat est déjà mis en cache, et si c'est le cas, il retourne le résultat mis en cache. Sinon, il calcule le résultat et le stocke dans le cache pour une utilisation future.
Usines de décorateurs
Parfois, vous pouvez vouloir créer des décorateurs qui peuvent être configurés avec des arguments. Cela peut être réalisé en utilisant une usine de décorateurs, qui est une fonction qui retourne un décorateur. Voici un exemple :
def repeat(n):
def decorator(func):
def wrapper():
result = ""
for _ in range(n):
result += func()
return result
return wrapper
return decorator
@repeat(3)
def say_hello():
return "hello "
print(say_hello()) ## Output: hello hello hello
Dans cet exemple, la fonction repeat
est une usine de décorateurs qui prend un argument n
et retourne un décorateur qui enveloppe la fonction d'origine, l'appelant n
fois et concaténant les résultats.
Ces techniques avancées de décorateurs démontrent la flexibilité et la puissance des décorateurs en Python. En utilisant des décorateurs, vous pouvez créer un code réutilisable, modulaire et facilement maintenable qui peut être facilement étendu et personnalisé pour répondre à vos besoins.