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

标签 python python-2.7 python-3.x exec

以下代码在 Python2Python3 中给出了不同的输出:

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

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

--- 编辑 ---

阅读 Martijns 的回答后,我用 Python3 进一步分析了这个问题。在下面的示例中,我将 locals() 字典作为 dexec,但是 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

比较dlocals()的id,发现是同一个对象。但在这些条件下,b 应该与 d['b'] 相同。我的示例有什么问题?

最佳答案

Python 2 中的 exec 和 Python 3 中的 exec() 有很大区别。你把 exec 当作一个函数,但它确实是 Python 2 中的一个语句

由于这种差异,您不能在 Python 3 中使用 exec 更改函数范围内的局部变量,即使在 Python 2 中是可能的。甚至以前声明的变量也不行。

locals() 只反射(reflect)一个方向的局部变量。以下内容在 2 或 3 中都不起作用:

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

在 Python 2 中,使用 exec 语句意味着编译器知道关闭局部作用域优化(从 LOAD_FAST 切换到 LOAD_NAME例如,在局部和全局范围内查找变量)。由于 exec() 是一个函数,该选项不再可用并且函数作用域现在总是优化。

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

正确的解决方法是为您的 exec() 调用使用新的命名空间(字典):

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

exec() documentation对这个限制非常明确:

Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

关于python - Python 2 和 Python 3 中 exec 函数的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40638179/

相关文章:

python - 如何将字符串模型字段转换为 Flask-Admin 中的选择输入?

python - 计数行号使用 python

python - 如何在这段Python代码中迭代元组?

python - 如何从 Python 中的十六进制字符串中删除 '\x'?

Python 2.7 打印()错误

python - 为什么 PyInstaller 没有检测到请求模块?

Python 日期时间与顺序问题

python-3.x - 需要精简版的 Libav 或 FFmpeg 才能使用 python

python - 在二十一点中找到多手牌的总数

Python 字典 : why and when I have to use sometimes ":" and sometimes "=" between the key and the value?