Xavier Lamorlette
Sommaire :
Un décorateur permet d'envelopper une fonction en la modifiant. Un décorateur prend une fonction en argument et retourne une fonction.
from functools import wraps
def print_arguments(function):
@wraps(function)
def wrapper(*args, **kwargs):
print(f"Arguments: {args} {kwargs}")
return function(*args, **kwargs)
return wrapper
@print_arguments
def a_function(a, b): ...
Ajouter @print_arguments
au-dessus de def a_funtion()
équivaut à :
def a_function(a, b): ...
a_funtion = print_arguments(a_function)
L'utilisation, optionnelle, de @wraps permet de conserver le nom et la docstring de la fonction lors de l'introspection du code.
On peut définir un décorateur via une classe qui implémente la méthode __call__()
:
from typing import Callable
class CallsCounter:
_function: Callable
_nb_calls: int = 0
def __init__(self,
function: Callable):
self._function = function
def __call__(self, *args, **kwargs):
self._nb_calls += 1
return self._function(*args, **kwargs)
@CallsCounter
def a_function(a, b): ...
from typing import Callable
from functools import wraps
class ActorWithErrorCallback:
_on_error: Callable[[Exception, str], None]
def __init__(self,
on_error: Callable[[Exception, str], None]):
self._on_error = on_error
def _try_except(message: str):
def decorator(function):
@wraps(function)
def wrapper(self, *args, **kwargs):
try:
function(self, *args, **kwargs)
except Exception as error:
self._on_error(error, message)
return wrapper
return decorator
class Actor(ActorWithErrorCallback):
@ActorWithErrorCallback._try_except("Error while doing toto")
def toto(self, a, b):
print(f"Actor.toto(): a={a}, b={b}")
raise RuntimeError("the error")
def on_error(error: Exception,
message: str):
print(f"{message}: {error}")
actor = Actor(on_error)
actor.toto(1, 2)
from typing import Callable
from functools import wraps
def try_except(on_error: Callable[[Exception, str], None],
message: str):
def decorator(function):
@wraps(function)
def wrapper(*args, **kwargs):
try:
function(*args, **kwargs)
except Exception as error:
on_error(error, message)
return wrapper
return decorator
class Actor:
_on_error: Callable[[Exception, str], None]
def __init__(self,
on_error: Callable[[Exception, str], None]):
self._on_error = on_error
self.toto = try_except(self._on_error, "Error while doing toto")(self.toto)
def toto(self, a, b):
print(f"Actor.toto(): a={a}, b={b}")
raise RuntimeError("the error")
def on_error_callback(error: Exception,
message: str):
print(f"{message}: {error}")
actor = Actor(on_error_callback)
actor.toto(1, 2)
On peut définir un attribut de fonction pour un wrapper. Exemple :
count_calls(function):
@wraps(function)
def wrapper(*args, **kwargs):
wrapper.nb_calls += 1
print(f"{function.__name__} called {wrapper.nb_calls} times")
return function(*args, **kwargs)
wrapper.nb_calls = 0
return wrapper
La dernière mise à jour de cette page date de mai 2024.
Le contenu de ce site est, en tant qu'œuvre originale de l'esprit, protégé par le droit d'auteur.
Pour tout commentaire, vous pouvez m'écrire à xavier.lamorlette@gmail.com.