classification
Title: eval of comprehension cannot access local variables
Type: behavior Stage: resolved
Components: Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Martin Hosken, eamanu, pekka.klarck, terry.reedy
Priority: normal Keywords:

Created on 2019-03-15 10:44 by Martin Hosken, last changed 2019-06-07 14:56 by pekka.klarck. This issue is now closed.

Messages (6)
msg337980 - (view) Author: Martin Hosken (Martin Hosken) Date: 2019-03-15 10:44
The following code fails:

    >>> lcls = {'w': 100}
    >>> eval('[w for x in ("hello", "world")]', None, lcls)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<string>", line 1, in <module>
      File "<string>", line 1, in <listcomp>
    NameError: name 'w' is not defined
    >>> eval('[w, w, w]', None, lcls)
    [100, 100, 100]

whereas in python2 it succeeds

    >>> lcls = {'w': 100}
    >>> eval('[w for x in ("hello", "world")]', None, lcls)
    [100, 100]
msg337981 - (view) Author: Emmanuel Arias (eamanu) * Date: 2019-03-15 12:01
I test it on 3.7 and 3.8 and have the same problem
msg337984 - (view) Author: Emmanuel Arias (eamanu) * Date: 2019-03-15 12:44
I don't know if this a bug for py3 or py2 because the the w variable
is not defined on the list comprehension context.

Maybe the locals on `eval` must be create w on locals context
msg338036 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-03-15 21:11
You example is a list comprehension, but no matter.  In 3.x, the value of a comprehension is the result of calling a temporary function.  Functions access globals and nonlocals but not non-global locals of surrounding contexts.  Class locals are an example of the latter.

>>> class C:
...   w = 100
...   l = [w for x in ("hello", "world")]
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in C
  File "<stdin>", line 3, in <listcomp>
NameError: name 'w' is not defined

To see this, one must make sure that the name in question is not also in globals, as it is below.

>>> w = 50
>>> [w for x in ("hello", "world")]
[50, 50]
>>> class C:
...   w = 100
...   l = [w for x in ("hello", "world")]
...
>>> C.l
[50, 50]  # Evaluated global w, not local w.

When one calls eval with separate globals and locals, one is simulating class context.  There should be a FAQ entry about this.
msg344948 - (view) Author: Pekka Klärck (pekka.klarck) Date: 2019-06-07 14:54
More ways to be bitten by this strange behavior:

    >>> d = {'a': 1, 'b': 2}
    >>> eval('[x[k] for k in x]', {}, {'x': d})
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<string>", line 1, in <module>
      File "<string>", line 1, in <listcomp>
    NameError: name 'x' is not defined
    >>> 
    >>> def f():
    ...     x = {'a': 1, 'b': 2}
    ...     return eval('[x[k] for k in x]')
    ... 
    >>> f()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in f
      File "<string>", line 1, in <module>
      File "<string>", line 1, in <listcomp>
    NameError: name 'x' is not defined



In both of the above cases changing

    eval('[x[k] for k in x]')

to

    eval('[v for v in x.values()]')

avoids the problem. There are no problems when using

    [x[k] for k in x]

without `eval()` either. I'd prefer this to be changed, but there should at least be a note in the documentation of `eval()` about this.
msg344949 - (view) Author: Pekka Klärck (pekka.klarck) Date: 2019-06-07 14:56
I encountered this issue because Robot Framework -- a generic Python based test automation framework -- supports evaluating Python expressions and this issue was reported for us:
https://github.com/robotframework/robotframework/issues/3207
History
Date User Action Args
2019-06-07 14:56:27pekka.klarcksetmessages: + msg344949
2019-06-07 14:54:57pekka.klarcksetnosy: + pekka.klarck
messages: + msg344948
2019-03-15 21:11:09terry.reedysetstatus: open -> closed


title: eval of generator expressions cannot access local variables -> eval of comprehension cannot access local variables
nosy: + terry.reedy
versions: - Python 2.7, Python 3.6
messages: + msg338036
resolution: not a bug
stage: resolved
2019-03-15 12:44:49eamanusettype: behavior
messages: + msg337984
versions: + Python 2.7
2019-03-15 12:01:53eamanusetnosy: + eamanu

messages: + msg337981
versions: + Python 3.7, Python 3.8
2019-03-15 10:45:03Martin Hoskensetversions: + Python 3.6
2019-03-15 10:44:12Martin Hoskencreate