为什么在exec中关闭了闭包?

时间:2010-05-01 10:59:11

标签: python closures exec

在Python 2.6中,

>>> exec "print (lambda: a)()" in dict(a=2), {}
2
>>> exec "print (lambda: a)()" in globals(), {'a': 2}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
  File "<string>", line 1, in <lambda>
NameError: global name 'a' is not defined
>>> exec "print (lambda: a).__closure__" in globals(), {'a': 2}
None

我希望它打印2两次,然后打印一个带有cell的元组。这与3.1中的情况相同。发生了什么事?

1 个答案:

答案 0 :(得分:25)

当您将字符串传递给execeval时,它会在考虑全局变量或本地变量之前将该字符串编译为代码对象。所以当你说:

eval('lambda: a', ...)

意思是:

eval(compile('lambda: a', '<stdin>', 'eval'), ...)

compile无法知道a是freevar,因此它将其编译为全局引用:

>>> c= compile('lambda: a', '<stdin>', 'eval')
>>> c.co_consts[0]
<code object <lambda> at 0x7f36577330a8, file "<stdin>", line 1>
>>> dis.dis(c.co_consts[0])
  1           0 LOAD_GLOBAL              0 (a)
              3 RETURN_VALUE        

因此,要使其工作,您必须将a放在全局变量而不是本地变量中。

是的,这有点狡猾。但那时我认为execeval对你来说......他们不应该很好。