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

Reply via email to