Même si cette question a déjà été répondu et accepté, j'aimerais vous montrer une idée qui est à mon humble avis tout à fait élégante. La solution proposée par t.dubrownik montre un modèle qui est toujours le même: vous avez besoin de trois couches wrapper indépendamment de ce que le décorateur.
J'ai donc enseigné que c'est un travail pour une méta-décorateur, qui est un décorateur pour les décorateurs. Un décorateur est une fonction, il fonctionne en fait comme un régulier décorateur avec des arguments:
def parametrized(dec):
def layer(*args, **kwargs):
def repl(f):
return dec(f, *args, **kwargs)
return repl
return layer
Ceci peut être appliqué à un régulière décorateur afin d'ajouter des paramètres. Ainsi, par exemple, disons que nous avons le décorateur qui double le résultat d'une fonction:
def double(f):
def aux(*xs, **kws):
return 2 * f(*xs, **kws)
return aux
@double
def function(a):
return 10 + a
print function(3) # Prints 26, namely 2 * (10 + 3)
Avec @parametrized
nous pouvons construire un générique @multiply
décorateur d'avoir un paramètre
@parametrized
def multiply(f, n):
def aux(*xs, **kws):
return n * f(*xs, **kws)
return aux
@multiply(2)
def function(a):
return 10 + a
print function(3) # Keeps printing 26
@multiply(3)
def function_again(a):
return 10 + a
print function(3) # Prints 39, namely 3 * (10 + 3)
Classiquement le premier paramètre d'une paramétrées, décorateur est la fonction, tandis que les autres arguments correspond au paramètre de la paramétrées, décorateur.
Un intéressant exemple d'utilisation pourrait être un type sûr autoritaire décorateur:
import itertools as it
@parametrized
def types(f, *types):
def rep(*args):
for a, t, n in zip(args, types, it.count()):
if type(a) is not t:
raise TypeError('Value %d has not type %s. %s instead' %
(n, t, type(a))
)
return f(*args)
return rep
@types(str, int) # arg1 is str, arg2 is int
def string_multiply(text, times):
return text * times
print(string_multiply('hello', 3)) # prints hellohellohello
print(string_multiply(3, 3)) # Fails miserably with TypeError