understanding generators and functions with arguments

C

caw

this is the smallest bit of code I could get to demonstrate what I
want to understand...

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!")


~/src/python caw$ python dec_play.py
Hello, world!

OK... so I can give a decorator and argument, and that will then
return the function <decorate>. This expects one argument (and is a
decorator (?)). When decorate is called with f1 as the argument, it
returns new_f, which, when called will print <text> (passed to the
original decorator), together with the result of calling f1 with its
args.

I don't understand the scope of *args, as seen in the argument list of
new_f. It doesn't appear to be in the static scope of msg, or decorate
or new_f...

Could someone help me with this...

Thanks

chris wright
 
S

Scott David Daniels

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 ....
I don't understand the scope of *args, as seen in the argument list of
new_f. It doesn't appear to be in the static scope of msg, or decorate
or new_f...
OK, I would probably write this as:
def msg(text):
def decorate(f):
def new_f(*args, **kwargs):
print text, f(*args, **kwargs)
return new_f
return decorate

That is, the *args in your example, and my "*args, **kwargs" are both
meant to represent the parameters passed to the "wrapped" function f.
My example would allow a line in the main section:

f1(s=42)

while your form would fail on that call.

-Scott David Daniels
(e-mail address removed)
 
S

Steven Bethard

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 decorate(f):
.... def new_f(*args, **kwds):
.... print text, f(*args, **kwds)
.... return new_f
.... return decorate
........ return s
........ def f1(s):
.... return s
....('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
 
T

Terry Reedy

this is the smallest bit of code I could get to demonstrate what I
want to understand...

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!")


~/src/python caw$ python dec_play.py
Hello, world!

OK... so I can give a decorator and argument, and that will then
return the function <decorate>. This expects one argument (and is a
decorator (?)). When decorate is called with f1 as the argument, it
returns new_f, which, when called will print <text> (passed to the
original decorator), together with the result of calling f1 with its
args.

I don't understand the scope of *args, as seen in the argument list of
new_f. It doesn't appear to be in the static scope of msg, or decorate
or new_f...

As with all parameters, 'args' is a local variable in the local namespace
of the function it is a parameter for, in this case new_f. I presume you
would call that 'local scope'. I do not know what you mean by 'static
scope' since that is not a term usually used in describing Python.

Terry J. Reedy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top