So, briefly on the topic of lexical scope, what does the following print?
def f():
funcs = []
for i in range(5):
def g():
print i
funcs.append(g)
return funcs
funcs = f()
for func in funcs:
func()
So, briefly on the topic of lexical scope, what does the following print?
def f():
funcs = []
for i in range(5):
def g():
print i
funcs.append(g)
return funcs
funcs = f()
for func in funcs:
func()
4 comments:
Python scopes at the function level, so framing 'i' as an argument to another local function will produce the expected output.
def f():
funcs = []
for i in range(5):
def close(i):
def g():
print i
return g
funcs.append(close(i))
return funcs
funcs = f()
for func in funcs:
func()
In addition, closures in python are read only, so g can't modify i either. The java-like workaround for that is to use mutable collections, but thats just annoying. JavaScript (originating in Scheme) does this a little better, having mutable closures and a new "let" keyword that provides lexical binding without a function call.
JavaScript folks run into this one somewhat often, and Vinny's transformation is what I've always used. I hadn't realized that the "let" keyword provided a workaround, that's excellent. JavaScript's "let" also allows tuple/destructuring assignment, which is a python nicety that I occasionally miss.
@ynniv That's a particularly nice solution. I'm guessing you're also aware of the partial function in functools (requires Python 2.5) which makes this even more concise:
def f():
funcs = []
for i in range(5):
def g(i):
print i
funcs.append(partial(g, i))
return funcs
I still can't help but laugh when some stubborn OO folks can't see the use of higher order functions!
needless to say, i am stumped as to how to preserve whitespace in a blogger comment ... :(
Post a Comment