On Wed, May 26, 2010 at 11:48, Mark Dickinson <dicki...@gmail.com> wrote:

> On Wed, May 26, 2010 at 10:15 AM, Colin H <hawk...@gmail.com> wrote:
> >   issue991196 was closed being described as intentional.  I've added
> > a comment in that issue which argues that this is a serious bug (also
> > aserted by a previous commenter - Armin Rigo), because it creates a
> > unique, undocumented, oddly behaving scope that doesn't apply closures
> > correctly. At the very least I think this should be acknowledged as a
> > plain old bug (rather than a feature), and then a discussion about
> > whether it will be fixed or not.
>
> Here's a quick recap of the issue so that people don't have to go
> searching through the bug archive.  In Python 2.x, we get the
> following behaviour:
>
> >>> code = """\
> ... y = 3
> ... def f():
> ...     return y
> ... f()
> ... """
> >>> exec code in {}   # works fine
> >>> exec code in {}, {}   # dies with a NameError
> Traceback (most recent call last):
>  File "<stdin>", line 1, in <module>
>  File "<string>", line 4, in <module>
>  File "<string>", line 3, in f
> NameError: global name 'y' is not defined
>
> The issue is whether the second example should work, given that two
> different dictionaries have been passed.
>
> The cause of the NameError can be seen by looking at the bytecode: y
> is bound using STORE_NAME, which stores y into the locals dictionary
> (which here is *not* the same as the globals dictionary) but the
> attempt to retrieve the value of y uses LOAD_GLOBAL, which only looks
> in the globals.
>
> >>> co = compile(code, 'mycode', 'exec')
> >>> dis.dis(co)
>  1           0 LOAD_CONST               0 (3)
>              3 STORE_NAME               0 (y)
>
>  2           6 LOAD_CONST               1 (<code object f at
> 0xa22b40, file "mycode", line 2>)
>              9 MAKE_FUNCTION            0
>             12 STORE_NAME               1 (f)
>
>  4          15 LOAD_NAME                1 (f)
>             18 CALL_FUNCTION            0
>             21 POP_TOP
>             22 LOAD_CONST               2 (None)
>             25 RETURN_VALUE
> >>> dis.dis(co.co_consts[1])  # disassembly of 'f'
>  3           0 LOAD_GLOBAL              0 (y)
>              3 RETURN_VALUE
>
> This is a long way from my area of expertise (I'm commenting here
> because it was me who sent Colin here in the first place), and it's
> not clear to me whether this is a bug, and if it is a bug, how it
> could be resolved.  What would the impact be of having the compiler
> produce 'LOAD_NAME' rather than 'LOAD_GLOBAL' here?


It wouldn't matter. The 'f' function only knows about its own namespace
(separate from the surrounding code's local namespace), and the global
namespace. LOAD_NAME is only different from LOAD_GLOBAL in that it looks in
the local namespace first, but in this case the local namespace contains
nothing. Here's what happens:

'exec code in d1, d2' executes code with 'd1' as locals and 'd2' as globals.
Assignment always operates on the local namespace (barring the 'global'
declaration.) The function definition also assigns to the local namespace,
but the created function knows nothing about that local namespace -- it only
cares about its own namespace and the global namespace, 'd1'.

'exec code in d1' does the same thing as 'exec code in d1, d1': it uses the
same dict for the locals and the globals. The execution of the code doesn't
change -- the assignment to 'y' still assigns to the locals, and the 'f'
function still looks it up in globals, but now *they are the same dict*.
Using the same dict for locals and globals is how modules work, as well.

The main confusion here is the fact that 'exec' doesn't generate closures.
(Nobody was ever confused about this behaviour back in Python
2.0-and-earlier! :-) The reason for that is the disconnect between the
compiler and the exec statement: the compiler sees no enclosing function, so
it doesn't generate a closure. The exec statement, because it gets two
different namespaces, then executes it like a function, with a distinct
local namespace.

-- 
Thomas Wouters <tho...@python.org>

Hi! I'm a .signature virus! copy me into your .signature file to help me
spread!
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to