13

在 Python 3 中执行以下操作没有错误:

code = """
import math

def func(x):
    return math.sin(x)

func(10)
"""
_globals = {}
exec(code, _globals)

但是,如果我也尝试捕获局部变量 dict ,它会失败并显示NameError

>>> _globals, _locals = {}, {}
>>> exec(code, _globals, _locals)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-9-aeda81bf0af1> in <module>()
----> 1 exec(code, {}, {})

<string> in <module>()

<string> in func(x)

NameError: name 'math' is not defined

为什么会发生这种情况,如何在捕获全局变量和局部变量的同时执行此代码?

4

1 回答 1

14

exec()文档中:

请记住,在模块级别,全局变量和局部变量是同一个字典。如果exec获得两个单独的对象作为globalslocals,则代码将被执行,就好像它嵌入在类定义中一样。

您传入了两个单独的字典,但尝试执行需要模块范围全局变量可用的代码。import math在一个类中会产生一个局部范围属性,并且您创建的函数将无法访问它,因为函数闭包不考虑类范围名称。

请参阅Python 执行模型参考中的命名和绑定:

类定义块和参数在名称解析的上下文中是特殊的exec()eval()类定义是可以使用和定义名称的可执行语句。这些引用遵循名称解析的正常规则,但在全局命名空间中查找未绑定的局部变量除外。类定义的命名空间成为类的属性字典。类块中定义的名称范围仅限于类块;它没有扩展到方法的代码块[.]

您可以通过尝试执行类定义中的代码来重现错误:

>>> class Demo:
...     import math
...     def func(x):
...         return math.sin(x)
...     func(10)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in Demo
  File "<stdin>", line 4, in func
NameError: name 'math' is not defined

只需传入本字典。

于 2016-09-22T19:44:01.970 回答