El decorador se invoca una sola vez, inmediatamente después de definir por primera vez la función decorada. Por lo tanto, estas dos técnicas (utilizando @wrap y bar = envoltura (bar)) son los mismos:
>>> def wrap(f):
... print 'making arr'
... arr = []
... def inner():
... arr.append(2)
... print arr
... f()
... return inner
...
>>> @wrap
... def foo():
... print 'foo was called'
...
making arr
>>> foo()
[2]
foo was called
>>> foo()
[2, 2]
foo was called
>>> def bar():
... print 'bar was called'
...
>>> bar = wrap(bar)
making arr
>>> bar()
[2]
bar was called
En ambos casos es evidente que se crea arr sólo cuando envoltura (f) se llama, y envoltura es llamado solo cuando foo y bar se declaran por primera vez.
En el caso de pasar argumentos a una función decorada, recuerde que un decorador toma una función como parámetro y devuelve una versión modificada de esa función. Entonces un decorador típicamente toma un parámetro, que es la función que está modificando. Devuelve una nueva función y el decorador puede definir la función que devuelve tomando cualquier cantidad de argumentos (por ejemplo, * args). El decorador puede incluso devolver una función que toma demasiados parámetros para el método que decora.
>>> def wrap_with_arg(f):
... def wrap(*args):
... print 'called with %d arguments' % len(args)
... f(args)
... return wrap
...
>>> @wrap_with_arg
... def baz(arg):
... print 'called with argument %r' % arg
...
>>> baz(3)
called with 1 arguments
called with argument 3
>>> baz(3, 4)
called with 2 arguments
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in wrap
File "<input>", line 3, in baz
TypeError: not all arguments converted during string formatting
Aunque finalmente Baz lanza un error, observe cómo el número de argumentos se imprime correctamente antes se lanza el error.
+1 gran respuesta. –
+1 también, sería interesante mencionar que se está creando un cierre y es por eso que es posible acceder a 'caché' cuando la función' defm' ya ha sido devuelta. – mmarinero
¡Gracias, ahora entiendo a los decoradores mucho mejor! :) –