python中的eval函数范围

时间:2014-12-09 12:10:46

标签: python eval python-internals

考虑以下示例:

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没有考虑函数内部定义的变量?从文档中,您可以选择传递全局变量和本地字典。这意味着什么?最后,我如何修改这个小案例才能使其发挥作用?

2 个答案:

答案 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()将是全局字典。请注意,函数内定义的ijk不在生成器的本地范围内,而是位于其封闭范围内:

>>> 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会将其与函数绑定,因为它是最近的封闭范围,但ik未在本地绑定(因为k isn'引用,i仅用于创建range)。


请注意,您可以通过以下方式避免此问题:

return dict(i=i, j=j, k=k)

或字典文字:

return {'i': i, 'j': j, 'k': k}