Appliquer plusieurs décorateurs
L'ordre d'application des décorateurs
Lorsque vous appliquez plusieurs décorateurs à une fonction, l'ordre dans lequel ils sont appliqués est important. Les décorateurs sont appliqués de bas en haut, ce qui signifie que le décorateur le plus interne est appliqué en premier, et le décorateur le plus externe est appliqué en dernier.
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def reverse(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result[::-1]
return wrapper
@uppercase
@reverse
def greet(name):
return f"Hello, {name}!"
print(greet("LabEx"))
Cela produira la sortie suivante :
!XEBAL,OLLEH
Empiler les décorateurs
Vous pouvez également empiler plusieurs décorateurs sur une seule fonction en les appliquant les uns après les autres. Cela équivaut à imbriquer les décorateurs, mais cela peut rendre le code plus lisible.
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def reverse(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result[::-1]
return wrapper
def greet(name):
return f"Hello, {name}!"
greet_upper_reverse = uppercase(reverse(greet))
print(greet_upper_reverse("LabEx"))
Cela produira la sortie suivante :
!XEBAL,OLLEH
Décorer des méthodes
Les décorateurs peuvent également être utilisés pour modifier le comportement des méthodes dans une classe. Les mêmes principes s'appliquent, mais la fonction décoratrice doit prendre le paramètre self
comme premier argument.
def log_method(func):
def wrapper(self, *args, **kwargs):
print(f"Calling {func.__name__} on {self.__class__.__name__} with args={args} and kwargs={kwargs}")
return func(self, *args, **kwargs)
return wrapper
class Person:
def __init__(self, name):
self.name = name
@log_method
def greet(self, message):
return f"{message}, {self.name}!"
person = Person("LabEx")
print(person.greet("Hello"))
Cela produira la sortie suivante :
Calling greet on Person with args=('Hello',) and kwargs={}
Hello, LabEx!
Décorer des classes
Les décorateurs peuvent également être utilisés pour modifier le comportement de classes entières. Dans ce cas, la fonction décoratrice prend une classe en argument et retourne une nouvelle classe avec le comportement souhaité.
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class MyClass:
def __init__(self, value):
self.value = value
obj1 = MyClass(42)
obj2 = MyClass(24)
print(obj1 is obj2) ## True
print(obj1.value) ## 42
print(obj2.value) ## 42
Dans cet exemple, le décorateur singleton
garantit qu'une seule instance de la classe MyClass
est créée, quelle que soit le nombre de fois où la classe est instanciée.