John wrote: > I noticed some odd behavior relating to eval(). First, a baseline case for > behavior: > >>>> def test(): > ... x = 5 > ... return [a for a in range(10) if a == x] > ... >>>> test() > [5] > > So far so good. Now let's try eval: > >>>> c = compile('[a for a in range(10) if a == x]', '', 'single') >>>> eval(c, globals(), {'x': 5}) > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > File "", line 1, in <module> > File "", line 1, in <listcomp> > NameError: global name 'x' is not defined > > Looks like 'x' is searched for only among the globals, bypassing the > locals. The same behavior is seen between exec and eval, with and without > compile, and between 3.1.3 and 3.2rc2. Given simpler code without a list > comp, the locals are used just fine: > >>>> c = compile('a=5; a==x', '', 'single') >>>> eval(c, {}, {'x': 5}) > True > > Could anyone help me understand these scoping rules? Thanks.
Except for class definitions the compiler statically determines whether a variable is global or local (or a closure). List comprehensions and generator expressions are realized as functions; therefore they have their own local scope that you cannot provide via eval/exec. You could argue that in the following example >>> exec("x = 2; print([a for a in range(3) if a == x])", {}, {}) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> File "<string>", line 1, in <listcomp> NameError: global name 'x' is not defined the assignment x = 2 should give the compiler a clue that x is supposed to be a local name, just like in def f(): x = 2 print([a for a in range(3) if a == x]) My *guess* is that this is an implementation restriction rather than a conscious decision. It works for the common case of module-level code because there local and global namespace are identical: >>> exec("x = 2; print([a for a in range(3) if a == x])", {}) [2] Peter _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor