Python 3.2.1:exec('x = y()') 在玩具示例中设置值,但不在完整代码中设置值



我使用exec()语句来设置一个值,如下所示:

foo = 3
def return_4():
    return 4
instruction = 'foo = return_4()'
exec(instruction)                     # <---- WHERE THE MAGIC HAPPENS
print(foo)

结果是4,正如我所料。

我的程序有操作魔方的操作。在这个简化的版本中,我将做四件事:

  1. 我将实例化一个立方体,填充一个面(使用"前左上角"one_answers"前右下角"等缩写)。

  2. 我将有一个旋转正面的函数。

  3. 我将有一个'解释器'函数,它接受一个多维数据集和一个指令列表,并将这些指令应用到多维数据集,返回修改后的多维数据集。这里是我使用'exec'的地方(我认为破损发生的地方)。

  4. 最后,我将在我的部分立方体上运行解释器,并指令旋转一次面。

+

my_cube = [['FTL', 'FTM', 'FTR',
            'FML', 'FMM', 'FMR',
            'FBL', 'FBM', 'FBR'],
            [],[],[],[],[]] # other faces specified in actual code
def rotate_front(cube):
    front = cube[0]
    new_front = [front[6],front[3],front[0],
                 front[7],front[4],front[1],
                 front[8],front[5],front[2]]
    # ...
    ret_cube = cube
    ret_cube[0] = new_front
    # pdb says we are returning a correctly rotated cube,
    # and calling this directly returns the rotated cube
    return ret_cube
def process_algorithm(cube=default_cube, algorithm=[]):
    return_cube = cube
    for instruction in algorithm:
        exec('return_cube = ' + instruction + '(return_cube)')  # <--- NO MAGIC!
        # ACCORDING TO pdb, return_cube HAS NOT BEEN ROTATED!
    return return_cube
process_algorithm(cube = my_cube, algorithm = ['rotate_front'])

如果我用x = eval(y)替换exec(x = y)形成,它似乎有效。Return_cube = eval(指令+ '(Return_cube)')

所以这可能只是学术上的。为什么玩具样例可以工作,而实际代码却失败了?(我是不是做了什么明显而愚蠢的事情,比如遗漏了一个等号?我打赌我要踢我自己…)

感谢大家的帮助。

x, exec是一个语句,它改变了变量查找从LOAD_GLOBALLOAD_FASTLOAD_NAME到您在函数上访问的每个名称。这意味着它首先搜索局部作用域,看看是否能在检查全局作用域后找到要查找的名称。

现在,在Python 3上。, exec函数不能更改此查找,并且永远不会找到您定义的名称,除非您使用

exec(some_code, globals())

要使其工作,您需要在函数中添加global my_var以确保查找工作。

请记住,这些东西将被插入到模块的全局命名空间中…

顺便说一句,你为什么需要execeval ?为什么不能在algorithm列表中添加真正的函数呢?


作为旁注,我可以看到你没有改变你的函数的algorithm变量,但如果你这样做,它会引入一些不想要的副作用,因为你创建的默认值是可变的,将在所有函数调用中使用。

为安全起见,请将其更改为None,并根据需要创建一个新列表

这并不试图回答问题,而是扩展了测试用例,以便更好地看到行为并保留以供参考。结果来自Windows上的Python 3.2.2。请参阅JBernardo的答案,以了解"为什么"会出现此行为。

从全局作用域("toy example"):

>>> foo = "global-foo"
>>> exec('foo = "global-bar"')
>>> foo
'global-bar'

在函数中(完整上下文):

>>> def setIt():
        foo = "local-foo"
        exec('foo = "local-bar"')
        return foo
foo = "global-foo"
>>> setIt()
'local-foo'
>>> foo
'global-foo'

指定globals()(对locals()根本不起作用):

>>> def setIt():
        foo = "local-foo"
        exec('foo = "local-bar"', globals())
        return foo
>>> foo = "global-foo"
>>> setIt()
'local-foo'
>>> foo
'local-bar'

快乐编码。

相关内容

  • 没有找到相关文章

最新更新