【问题标题】:Python eval doesn't work inside a function [duplicate]Python eval 在函数内不起作用 [重复]
【发布时间】:2016-12-19 16:15:47
【问题描述】:

为什么 Python 的 eval 不能在函数内工作?相同的eval(compile(cmd)) 代码在全局环境中有效,但在foo 函数内部无效。

简单示例:

fn = '/tmp/tmp'
mode = 'single'

def foo(cmd, fn, mode):
    eval(compile(cmd, fn, mode)) # <<< this does not work
    print 'foo: cmd=', cmd
    print 'foo: x=', x

cmd = "x = 1"
eval(compile(cmd, fn, mode)) # <<< this works
print 'global scope: cmd=', cmd
print 'global scope: x=', x

del(x)
foo('x = 9', fn, mode)

这是输出和错误信息:

global scope: cmd= x = 1
global scope: x= 1
foo: cmd= x = 9
foo: x=
Traceback (most recent call last):
  File "ctest.py", line 20, in <module>
    foo('x = 9', fn, mode)
  File "ctest.py", line 12, in foo
    print 'foo: x=', x
NameError: global name 'x' is not defined

【问题讨论】:

  • 您确定不想将其值分配给某个东西吗?
  • 刚试过这个:x 最终出现在 locals 字典中,就像它对 exec 所做的那样,但是虽然 exec(cmd) 在函数中起作用,eval(compile(...)) 却没有。
  • 另外,如果你在print 'foo: x=', x 中输入eval("x") 而不是x,它也可以工作。 Python 2.7 和 Python 3.4 中的行为相同

标签: python function global-variables exec eval


【解决方案1】:

在您的函数中,执行确实有效,但 xlocals() 结束,然后 print 语句尝试在 globals() 中找到 x 并因此引发 NameError

fn = '/tmp/tmp'
mode = 'single'

def foo(cmd, fn, mode):
    eval(compile(cmd, fn, mode))
    print 'locals:', locals()
    print 'foo: cmd=', cmd
    print 'foo: x=', locals()['x']

cmd = "x = 1"
eval(compile(cmd, fn, mode))
print 'global scope: cmd=', cmd
print 'global scope: x=', x

del(x)
foo('x = 9', fn, mode)

输出:

global scope: cmd= x = 1
global scope: x= 1
locals: {'x': 9, 'cmd': 'x = 9', 'mode': 'single', 'fn': '/tmp/tmp'}
foo: cmd= x = 9
foo: x= 9

【讨论】:

  • 刚刚注意到exec, x 确实最终出现在globalslocals 中;起初我认为两者都会产生相同的globalslocals。但是,是的,为什么它不调查locals,为什么eval("x") 可以工作,而x 却失败了?
  • 我认为函数中变量的范围是在定义时确定的。因此像a = "a"; def print_a(): print(a); a="c" 这样的东西会抛出一个UnboundLocalError。 eval("x")“创建一个新的完整查找”,因此可以查看本地范围。
  • @syntonym 这是一个有趣的理论,根据你的例子,它是有道理的,并且可以解释这种行为。你能提供一个参考吗?
  • @tobias_k 我认为它来自the scoping rules,但我无法准确指出它。也许有更多经验或时间的人可以参与进来。
猜你喜欢
  • 2017-06-24
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 2019-06-04
  • 2014-06-30
  • 2017-06-30
相关资源
最近更新 更多