[Python-Dev] Inconsistent nesting of scopes in exec(..., locals())

Nick Coghlan ncoghlan at gmail.com
Fri Apr 23 18:32:44 CEST 2010


Joachim B Haga wrote:
> There seem to be an inconsistency in the handling of local scopes in
> exec. Consider the following code, which raises NameError if the '#' is
> removed from the second last line.
> 
> 
> block = """
> b = 'ok'
> def f():
>     print(b)    # raises NameError here
> f()
> """
> scope = locals()#.copy()
> exec(block, globals(), scope)
> 
> 
> The intermediate scope is searched for the variable name if the third
> argument to exec() is locals(), but not if it is locals().copy().
> Testing further, it looks like NameError is raised for any dict which 
> is not identically equal to either globals() or locals().

What actually matters is whether or not the first and second scope are
the same dictionary or not.

If they're different, then the supplied local scope is treated as
equivalent to a class definition scope, and hence won't participate in
lexical scoping. If they're the same (which happens implicitly if the
second one is omitted) then they're treated as a module scope (and hence
written values are visible as globals inside any defined functions).

(Using 2.x syntax)

>>> outer_scope = dict()
>>> inner_scope = dict()
>>> block = """
... b = 'ok'
... def f():
...   print (b)
... f()
... """
>>> exec block in outer_scope
ok
>>> outer_scope.clear()
>>> exec block in outer_scope, outer_scope
ok
>>> outer_scope.clear()
>>> exec block in outer_scope, inner_scope
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 5, in <module>
  File "<string>", line 4, in f
NameError: global name 'b' is not defined

Since changing this would break class definitions, that ain't going to
happen. Suggestions for how to explain the behaviour more clearly in the
exec() documentation probably wouldn't hurt though.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------


More information about the Python-Dev mailing list