Python 2和Python 3中的exec函数的行为
以下代码在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
将execute
函数中的variablesb
绑定到exec
函数string中的值,而Python3
不这样做? 我如何在Python3
实现Python2
的行为? 我已经尝试将globals和locals的字典传递给Python3
exec
函数,但目前为止还没有任何工作。
—编辑—
在阅读Martijns的答案后,我进一步用Python3
分析了这个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
和locals()
的id的比较表明它们是同一个对象。 但在这种情况下, b
应该和d['b']
。 我的例子有什么问题?
Python 2中的exec
与Python 3中的exec()
之间有着很大的区别。你将exec
当作一个函数,但它确实是Python 2中的一个语句 。
由于这种差异,你不能在Python 3中使用exec
来更改函数范围中的局部variables,尽pipe在Python 2中是可能的。甚至没有先前声明的variables。
局部variableslocals()
只反映局部variables的方向。 以下从未在2或3工作:
def foo(): a = 'spam' locals()['a'] = 'ham' print(a) # prints 'spam'
在Python 2中,使用exec
语句意味着编译器知道closures本地范围优化(例如,从LOAD_FAST
切换到LOAD_NAME
,以便在本地和全局范围内查找variables)。 用exec()
函数,该选项不再可用,函数作用域现在总是被优化。
此外,在Python 2中, exec
语句将使用PyFrame_LocalsToFast
将所有在locals()
find的variables显式复制到函数本地,但PyFrame_LocalsToFast
是不提供全局variables和PyFrame_LocalsToFast
variables参数。
正确的解决方法是为你的exec()
调用使用一个新的命名空间(一个字典):
def execute(a, st): namespace = {} exec("b = {}\nprint('b:', b)".format(st), namespace) print(namespace['b'])
我会说这是一个python3的错误。
def u(): exec("a=2") print(locals()['a']) u()
打印“2”。
def u(): exec("a=2") a=2 print(a) u()
打印“2”。
但
def u(): exec("a=2") print(locals()['a']) a=2 u()
失败
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in u KeyError: 'a'
—编辑—另一个有趣的行为:
def u(): a=1 l=locals() exec("a=2") print(l) u() def u(): a=1 l=locals() exec("a=2") locals() print(l) u()
输出
{'l': {...}, 'a': 2} {'l': {...}, 'a': 1}
并且
def u(): l=locals() exec("a=2") print(l) print(locals()) u() def u(): l=locals() exec("a=2") print(l) print(locals()) a=1 u()
输出
{'l': {...}, 'a': 2} {'l': {...}, 'a': 2} {'l': {...}, 'a': 2} {'l': {...}}
显然, exec
对当地人的行为如下:
- 如果在
exec
设置了一个variables,并且这个variables是一个局部variables,那么exec
会修改内部字典(locals()
返回的字典),并且不会将其返回到原始状态。 对locals()
调用更新字典(如python文档的第2部分所述),并且exec
设置的值被遗忘。 调用locals()
来更新字典的需求并不是python3的一个bug,因为它被logging下来,但它并不直观。 此外,exec
中的局部variables不会改变函数的局部variables这一事实与python2是有文档上的区别的(文档中提到“如果需要在函数执行后查看代码对本地代码的影响,传递一个显式的局部variables字典)返回“),我更喜欢python2的行为。 - 如果在
exec
设置了一个variables,并且此variables之前不存在,那么exec
将修改内部字典,除非该variables是事后设置的。 似乎locals()
更新字典的方式有一个错误; 这个bug通过在exec
后调用locals()
来访问exec
设置的值。
恐怕我不能正确地解释它,但它基本上来自于函数内部的b是本地的,而exec()
似乎是分配给全局b的事实。 你必须在函数内声明b是全局的, 并且在exec语句中。
尝试这个:
from sys import version print(version) def execute1(a, st): b = 42 exec("b = {}\nprint('b:', b)".format(st)) print(b) def execute2(a, st): global b b = 42 exec("global b; b = {}\nprint('b:', b)".format(st)) print(b) a = 1. execute1(a, "1.E6*a") print() execute2(a, "1.E6*a") print() b = 42 exec("b = {}\nprint('b:', b)".format('1.E6*a')) print(b)
这给了我
3.3.0 (default, Oct 5 2012, 11:34:49) [GCC 4.4.5] b: 1000000.0 42 b: 1000000.0 1000000.0 b: 1000000.0 1000000.0
你可以看到,在这个函数之外,全局b被自动拾取。 在函数内部,你正在打印本地b。
请注意,我以为exec()
总是首先使用全局b,所以在execute2()
,你不需要在exec()
函数内声明它。 但我发现这是行不通的(这是我无法解释的部分)。