2

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

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

正如我所料,结果为 4。

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

  1. 我将实例化一个立方体,填充一个面(带有“front top left”和“front bottom right”等的缩写)。

  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)')

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

感谢任何人都可以提供的任何帮助。

4

2 回答 2

5

在 Python 2.x 上,exec有一条语句将变量查找从LOAD_GLOBALLOAD_FAST更改LOAD_NAME为您在函数上访问的每个名称。这意味着它首先搜索本地范围以查看是否可以在检查全局范围后找到名称。

现在,在 Python 3.x 上,该exec函数无法更改此查找并且永远不会找到您定义的名称,除非您添加一个具有您希望评估结果的范围的参数。

exec(some_code, globals())

为此,您需要global my_var在函数内部添加以确保查找正常工作。

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

顺便说一句,你为什么需要execor eval?为什么不能在algorithm列表中添加真正的功能?


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

为了安全起见,如果需要,请将其更改为None并创建一个新列表。

于 2012-01-02T00:59:18.923 回答
3

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

从全局范围(“玩具示例”):

>>> 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'

快乐编码。

于 2012-01-02T01:09:13.737 回答