考虑以下示例:
i=7
j=8
k=10
def test():
i=1
j=2
k=3
return dict((name,eval(name)) for name in ['i','j','k'])
它返回:
>>> test()
{'i': 7, 'k': 10, 'j': 8}
为什么eval没有考虑函数内部定义的变量?从文档中,您可以选择传递全局变量和本地字典。这意味着什么?最后,我如何修改这个小案例才能使其发挥作用?
答案 0 :(得分:13)
生成器implemented as function scopes:
类块中定义的名称范围仅限于该类 块;它没有扩展到方法的代码块 - 这个 包括生成器表达式,因为它们是使用a实现的 功能范围。
因此,dict()
构造函数中的生成器有自己的locals()
字典。现在让我们看看Py_eval
's source code,特别是当globals()
和locals()
都为无时:
if (globals == Py_None) {
globals = PyEval_GetGlobals();
if (locals == Py_None)
locals = PyEval_GetLocals();
}
因此,对于您的示例,{[3}}在循环执行时将为空,globals()
将是全局字典。请注意,函数内定义的i
,j
和k
不在生成器的本地范围内,而是位于其封闭范围内:
>>> dict((name,eval(name, globals(), {})) for name in ['i', 'j', 'k'])
{'i': 7, 'k': 10, 'j': 8}
答案 1 :(得分:4)
这是因为生成器表达式与函数具有不同的范围:
>>> def test():
i, j, k = range(1, 4)
return dict((j, locals()) for _ in range(i))
>>> test()
{2: {'.0': <listiterator object at 0x02F50A10>, 'j': 2, '_': 0}}
在范围内使用j
会将其与函数绑定,因为它是最近的封闭范围,但i
和k
未在本地绑定(因为k
isn'引用,i
仅用于创建range
)。
请注意,您可以通过以下方式避免此问题:
return dict(i=i, j=j, k=k)
或字典文字:
return {'i': i, 'j': j, 'k': k}