小能豆

Python 2 和 Python 3 中 exec 函数的行为

javascript

以下代码在Python2和 中给出不同的输出Python3

from sys import version

print(version)

def execute(a, st):
    b = 42
    exec("b = {}\nprint('b:', b)".format(st))
    print(b)
a = 1.
execute(a, "1.E6*a")

Python2印刷:

2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)]
('b:', 1000000.0)
1000000.0

Python3印刷:

3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
b: 1000000.0
42

为什么将函数内的Python2变量绑定到函数字符串中的值,而 while却不这样做?如何实现in的行为?我已经尝试将全局和局部的字典传递给in 函数,但到目前为止没有任何效果。b``execute``exec``Python3``Python2``Python3``exec``Python3

- - 编辑 - -

在阅读了 Martijns 的回答后,我进一步分析了这一点Python3。在下面的例子中,我给出了字典locals(),但打印的内容不仅仅是打印。d``exec``d['b']``b

from sys import version

print(version)

def execute(a, st):
    b = 42
    d = locals()
    exec("b = {}\nprint('b:', b)".format(st), globals(), d)
    print(b)                     # This prints 42
    print(d['b'])                # This prints 1000000.0
    print(id(d) == id(locals())) # This prints True
a = 1.
execute(a, "1.E6*a")

3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
b: 1000000.0
42
1000000.0
True

d和的 id 比较locals()表明它们是同一个对象。但在这种情况下b应该与 相同d['b']。我的示例中有什么问题?


阅读 60

收藏
2024-07-31

共1个答案

小能豆

execPython 2 和Python 3之间存在很大差异。exec()您将其视为exec一个函数,但在 Python 2 中它实际上是一个语句。

由于这个差异,你不能在 Python 3 中使用 来更改函数作用域内的局部变量exec,尽管在 Python 2 中可以这样做。甚至以前声明的变量也不行。

locals()仅反映一个方向上的局部变量。以下内容在 2 或 3 中从未起作用:

def foo():
    a = 'spam'
    locals()['a'] = 'ham'
    print(a)              # prints 'spam'

在 Python 2 中,使用exec语句意味着编译器知道关闭局部范围优化(例如从切换到LOAD_FASTLOAD_NAME在局部和全局范围内查找变量)。作为exec()函数,该选项不再可用,并且函数范围现在始终是经过优化的。

此外,在 Python 2 中,该exec语句明确地将在中找到的所有变量复制locals()回函数 locals 使用PyFrame_LocalsToFast,但前提是没有提供globalslocals参数。

正确的解决方法是使用一个新的命名空间(字典)进行调用exec()

def execute(a, st):
    namespace = {}
    exec("b = {}\nprint('b:', b)".format(st), namespace)
    print(namespace['b'])

文档对这个限制exec()说得非常明确:

注意:默认局部变量的作用如下函数所述:不应尝试locals()修改默认局部变量字典。如果您需要在函数返回后查看代码对局部变量的影响,请传递显式局部变量字典。exec()

2024-07-31