The decorator is called only once, right after a certain function is first defined. So these two methods (using @wrap and bar = wrap (bar)) are the same:
>>> 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
In both cases, it is clear that arr is only created when wrap (f) is called, and wrap is only called when foo and bar are declared first.
Regarding the case of passing arguments to a decorated function, remember that the decorator takes the function as a parameter and returns a modified version of this function. Therefore, the decorator usually takes one parameter, which is the function that it modifies. It returns a new function, and the decorator can define the function that it returns by accepting any number of arguments (e.g. * args). The decorator may even return a function that takes too many parameters for the method that it decorates.
>>> 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
While baz throws an error, note how the number of arguments is correctly printed before the error is reset.
Nolen Royalty
source share