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 | ncogh...@gmail.com | Brisbane, Australia --------------------------------------------------------------- _______________________________________________ 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