解决问题的方法就在这里:
在所有情况下,如果省略了可选部分,则代码将在当前范围内执行。 如果仅提供全局变量,则必须为字典,该字典将用于全局变量和局部变量。
如果给出了全局变量和局部变量,则它们分别用于全局变量和局部变量。如果提供的话,本地变量可以是任何映射对象。
请记住,在模块级别,全局变量和局部变量是相同的字典。 如果exec获得两个单独的对象作为全局对象和局部对象,则代码将像嵌入在类定义中一样执行。
https://docs.python.org/3/library/functions.html#exec
基本上,您的问题是bar的定义
locals仅在的范围内
locals。因此,此
exec()语句有效:
exec("""def bar(): return 1print(bar())""", {}, {})但是,列表理解会创建一个新的本地范围,该范围
bar未定义,因此无法查找。
此行为可以用以下方式说明:
exec("""def bar(): return 1print(bar())print(locals())print([locals() for _ in range(1)])""", {}, {})哪个返回
1{'bar': <function bar at 0x108efde18>}[{'_': 0, '.0': <range_iterator object at 0x108fa8780>}]编辑
在您的原始示例中,的定义
bar位于(模块级别)全局范围内。这对应于
请记住,在模块级别,全局变量和局部变量是相同的字典。
在
exec示例中,您通过传递两个不同的字典在全局变量和局部变量之间引入了一个人为的范围划分。如果您传递相同的一个或仅传递一个全局变量(这反过来意味着该变量将用于
globals和
locals),那么您的示例也将起作用。
至于在编辑中引入的示例,这可以归结为python中的作用域规则。有关详细说明,请阅读:https : //docs.python.org/3/tutorial/classes.html#python-
scopes-and-namespaces
简而言之,虽然
bar不在列表理解的本地范围内,也不在全局范围内,但它在foo范围内。根据给定的Python范围规则,如果在本地范围内找不到变量,则将在封闭范围内搜索该变量,直到达到全局范围为止。在您的示例中,foo的作用域位于本地作用域和全局作用域之间,因此bar将在到达搜索结束之前找到。
然而,这仍然与exec示例不同,在exec示例中,您传入的本地范围并不包含列表推导的范围,而是与其完全分开的。
可以在这里找到范围界定规则的另一种很好的解释,包括插图:http
:
//sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html



