understanding generators and functions with arguments
Steven Bethard
steven.bethard at gmail.com
Tue Oct 12 00:38:19 EDT 2004
<caw <at> southernhealth.org.au> writes:
>
> def msg(text):
> def decorate(f):
> def new_f(*args):
> print text, f(*args)
> return new_f
> return decorate
>
>
> @msg("Hello, ")
> def f1(s):
> return s
>
>
> if __name__ == '__main__':
> f1("world!")
[snip]
>
> I don't understand the scope of *args, as seen in the argument list of
> new_f.
Not sure if Scott's answer was sufficient for you. In case it wasn't, maybe
this will help illustrate a few more things:
>>> def msg(text):
... def decorate(f):
... def new_f(*args, **kwds):
... print text, f(*args, **kwds)
... return new_f
... return decorate
...
>>>
>>> def f1(s):
... return s
...
>>> f1.func_code.co_varnames
('s',)
>>>
>>> @msg("Hello, ")
... def f1(s):
... return s
...
>>> f1.func_code.co_varnames
('args', 'kwds')
So what's happening here is that f1 is being replaced by your function new_f.
Note that though the definition of f1 has an 's' argument, the definition of
f1 after the application of a decorator has the 'args' and 'kwds' arguments of
new_f.
When you call a function passed into a decorator (e.g. the 'f' passed
into 'decorate' in your example above) you won't necessarily know what
arguments it takes. Using *args and **kwds says that you don't know what
these arguments are, which is probably true in most cases when you write a
decorator function.
Note that if you knew you were only ever going to use this decorator for
function f1, you could write it as:
def msg(text):
def decorate(f):
def new_f(s):
print text, f(s)
return new_f
return decorate
and when f1 was replaced with new_f, your argument name would still be 's'.
Of course, then you could never use msg(...) as a decorator to any function
that took more than a single argument.
Steve
More information about the Python-list
mailing list