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