Local variable in a closure

I

Ian Kelly

f is nonlocal to times(), local to multiplier(). As the docs for the
locals() function say, "Free variables are returned by locals() when
it is called in function blocks, but not in class blocks."
 
D

Dave Angel


Please have a little respect, and include the source in your message.
You managed quite nicely to keep it small, but you put it in an obscure
place that some people won't be able to reach, and that might not
survive for the archives.

def multiplier(f):
def times(n):
# is f local?
nonlocal f
f=f+1
# if not, why is it here?
print("Locals: ",locals())
return n*f
return times

times2 = multiplier(2)
print(times2(4)) # 3X4=12
print(times2(4)) # 4X4=16

Inside function times, the variable 'f' is a free variable, not a local.
You can prove that to yourself by adding a dis.dis(times) just before
the "return times" statement. Here's how it begins:

7 0 LOAD_DEREF 0 (f)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 STORE_DEREF 0 (f)


In the dis.dis listing, the LOAD_DEREF and STORE_DEREF opcodes are
referring to free variables, the LOAD_FAST is referring to a local, and
the LOAD_GLOBAL is referring to a global.

The locals() function is just over-simplifying. it's only a convenience
function, not what I would consider part of the language, and it wasn't
apparently deemed necessary to have a separate function for debugging
free varaibles.
 
T

Terry Reedy

Please have a little respect, and include the source in your message.
You managed quite nicely to keep it small, but you put it in an obscure
place that some people won't be able to reach, and that might not
survive for the archives.

def multiplier(f):
def times(n):
# is f local?
nonlocal f
f=f+1
# if not, why is it here?
print("Locals: ",locals())

Because nonlocal names are not in the global dict and the devs wanted
globals() + locals() to report all accessible names, rather than add
nonlocals() or leave them invisible.
return n*f
return times

times2 = multiplier(2)
print(times2(4)) # 3X4=12
print(times2(4)) # 4X4=16

Inside function times, the variable 'f' is a free variable, not a local.
You can prove that to yourself by adding a dis.dis(times) just before
the "return times" statement. Here's how it begins:

7 0 LOAD_DEREF 0 (f)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 STORE_DEREF 0 (f)

In the dis.dis listing, the LOAD_DEREF and STORE_DEREF opcodes are
referring to free variables, the LOAD_FAST is referring to a local, and
the LOAD_GLOBAL is referring to a global.

The locals() function is just over-simplifying. it's only a convenience
function, not what I would consider part of the language,

I think this is a good way to look at it.
and it wasn't apparently deemed necessary to have a separate function
for debugging free varaibles.

One should think of 'locals' as meaning 'non_globals', which was exactly
true when there were no non-global, non-local names. When closures were
first added, such names were only readable. There was a long debate over
what term to use for the keyword that would allow rebinding the names in
outer functions. 'Nonlocal' is, at best, the least bad of the options
considered.

In standard usage, the terms 'free' and 'bound' are context dependent.
https://en.wikipedia.org/wiki/Free_variable
Within a function or class body, all global variables are non-local and
free, just like 'nonlocals'.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top