python exec 在 2.7 和 3.3 之间表现不同

python exec behaving differently between 2.7 and 3.3

下面的代码片段从 Python 2.7 和 3.3 获得不同的输出。

data = {'_out':[1,2,3,3,4]}
codes = ['_tmp=[]',
         '[_tmp.append(x) for x in _out if x not in _tmp]',
         'print(_tmp)']
for c in codes:
    exec(c,{},data)

来自 Python 2.7 的输出:

[1,2,3,4]

来自 Python 3.3 的输出:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    exec(c,{},data)
  File "<string>", line 1, in <module>
  File "<string>", line 1, in <listcomp>
NameError: global name '_tmp' is not defined

为了修复Python 3.3 中的错误,我只是将全局变量设置为与局部变量相同,即exec(c,data,data)。知道为什么 Python 3.3 的行为与 2.7 不同吗?

它似乎是已知的并且需要行为,请参阅问题 13557 https://bugs.python.org/issue13557

以及

https://docs.python.org/3/reference/executionmodel.html#interaction-with-dynamic-features

The eval() and exec() functions do not have access to the full environment for resolving names. Names may be resolved in the local and global namespaces of the caller. Free variables are not resolved in the nearest enclosing namespace, but in the global namespace.

您可以通过不对局部变量方法调用使用列表理解,或者通过全局范围提供变量来解决上述问题

改为循环

data = {'_out':[1,2,3,3,4]}
codes = ['_tmp=[]', """
for x in _out: 
  if x not in _tmp: 
    _tmp.append(x)
""",
         'print(_tmp)']

for c in codes:
    exec(c, {}, data)

全球环境

data = {'_out':[1,2,3,3,4]}
codes = ['_tmp=[]',
         '[_tmp.append(x) for x in _out if x not in _tmp]',
         'print(_tmp)']
for c in codes:
    exec(c, data)