Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #52652 > unrolled thread

Local variable in a closure

Started byw.w.milner@googlemail.com
First post2013-08-18 02:41 -0700
Last post2013-08-18 16:42 -0400
Articles 5 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  Local variable in a closure w.w.milner@googlemail.com - 2013-08-18 02:41 -0700
    Re: Local variable in a closure Chris Angelico <rosuav@gmail.com> - 2013-08-18 11:28 +0100
    Re: Local variable in a closure Ian Kelly <ian.g.kelly@gmail.com> - 2013-08-18 04:40 -0600
    Re: Local variable in a closure Dave Angel <davea@davea.name> - 2013-08-18 10:44 +0000
    Re: Local variable in a closure Terry Reedy <tjreedy@udel.edu> - 2013-08-18 16:42 -0400

#52652 — Local variable in a closure

Fromw.w.milner@googlemail.com
Date2013-08-18 02:41 -0700
SubjectLocal variable in a closure
Message-ID<107941d9-a981-4dd6-8460-336afc16f025@googlegroups.com>
Is f local or not?
http://pastebin.com/AKDJrbDs

[toc] | [next] | [standalone]


#52653

FromChris Angelico <rosuav@gmail.com>
Date2013-08-18 11:28 +0100
Message-ID<mailman.24.1376821729.23369.python-list@python.org>
In reply to#52652
On Sun, Aug 18, 2013 at 10:41 AM,  <w.w.milner@googlemail.com> wrote:
> Is f local or not?
> http://pastebin.com/AKDJrbDs

With something that short, it'd be easier to simply paste it straight
into your post, rather than having it off elsewhere. But to answer
your question: It is its own kind of beast. You can play around with
the dis.dis() function (start with "import dis", which is not just
"import this" with an accent) in the interactive interpreter, as an
effective way of finding out what actually happens. In my testing, the
opcodes for retrieving and updating 'f' are LOAD_DEREF and
STORE_DEREF, different from LOAD_FAST/STORE_FAST as used for locals,
and LOAD_GLOBAL/STORE_GLOBAL for globals. In normal usage, nonlocal
variables are most like local variables, but they happen to span one
level of function nesting. So they're still basically locals, hence
they appear in locals(). At least, that's my understanding of it.

ChrisA

[toc] | [prev] | [next] | [standalone]


#52654

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-08-18 04:40 -0600
Message-ID<mailman.25.1376822460.23369.python-list@python.org>
In reply to#52652
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."

On Sun, Aug 18, 2013 at 3:41 AM,  <w.w.milner@googlemail.com> wrote:
> Is f local or not?
> http://pastebin.com/AKDJrbDs
> --
> http://mail.python.org/mailman/listinfo/python-list

[toc] | [prev] | [next] | [standalone]


#52655

FromDave Angel <davea@davea.name>
Date2013-08-18 10:44 +0000
Message-ID<mailman.26.1376822665.23369.python-list@python.org>
In reply to#52652
w.w.milner@googlemail.com wrote:

> Is f local or not?
> http://pastebin.com/AKDJrbDs

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.

-- 
DaveA

[toc] | [prev] | [next] | [standalone]


#52662

FromTerry Reedy <tjreedy@udel.edu>
Date2013-08-18 16:42 -0400
Message-ID<mailman.3.1376858584.19984.python-list@python.org>
In reply to#52652
On 8/18/2013 6:44 AM, Dave Angel wrote:
> w.w.milner@googlemail.com wrote:
>
>> Is f local or not?
>> http://pastebin.com/AKDJrbDs
>
> 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'.

-- 
Terry Jan Reedy

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web