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

Bro*_*bat 2 python exec rubiks-cube

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

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

正如我所料,这是4.

我的程序有操作Rubik的立方体的操作.在这个精简版中,我会做四件事:

  1. 我将实例化一个立方体,填充一个面(缩写为"前左上"和"前右下"等).

  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'])
Run Code Online (Sandbox Code Playgroud)

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

所以也许这只是学术上的.为什么玩具示例有效,实际代码失败?(我是在做一些明显而愚蠢的事情,比如错过一个等号吗?我打算踢自己,我打赌......)

感谢任何人都能提供的帮助.

JBe*_*rdo 5

关于Python 2.x的,exec是从改变变量查找一份声明LOAD_GLOBAL,并LOAD_FASTLOAD_NAME你在你的函数访问每一个名字.这意味着它首先搜索本地范围,以查看是否可以在检查全局范围后找到该名称.

现在,在Python 3.x上,该exec函数无法更改此查找,并且永远不会找到您定义的名称,除非您使用要对结果进行求值的范围添加参数.

exec(some_code, globals())
Run Code Online (Sandbox Code Playgroud)

为此,您需要global my_var在函数内部添加以确保查找起作用.

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

顺便说一句,你为什么需要execeval?为什么不能在algorithm列表中添加实际功能?


作为旁注,我可以看到你没有更改algorithm你的函数的var,但是如果你这样做会引入一些不受欢迎的副作用,因为你创建的默认值是可变的并且将用于所有函数调用.

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