Behavior of exec function in Python 2 and Python 3
以下代码在
1 2 3 4 5 6 7 8 9 10 11 | from sys import version print(version) def execute(a, st): b = 42 exec("b = {} print('b:', b)".format(st)) print(b) a = 1. execute(a,"1.E6*a") |
1 2 3 | 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] ('b:', 1000000.0) 1000000.0 |
1 2 3 | 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)] b: 1000000.0 42 |
为什么
---编辑---
在阅读Martijns回答后,我用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from sys import version print(version) def execute(a, st): b = 42 d = locals() exec("b = {} print('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 |
Python 2中的
由于存在这种差异,您无法使用
1 2 3 4 | def foo(): a = 'spam' locals()['a'] = 'ham' print(a) # prints 'spam' |
在Python 2中,使用
此外,在Python 2中,
正确的解决方法是为
1 2 3 4 5 | def execute(a, st): namespace = {} exec("b = {} print('b:', b)".format(st), namespace) print(namespace['b']) |
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 functionexec() returns.
我会说这是python3的一个bug。
1 2 3 4 | def u(): exec("a=2") print(locals()['a']) u() |
打印"2"。
1 2 3 4 5 | def u(): exec("a=2") a=2 print(a) u() |
打印"2"。
但
1 2 3 4 5 | def u(): exec("a=2") print(locals()['a']) a=2 u() |
失败了
1 2 3 4 | Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 3, in u KeyError: 'a' |
---编辑---
另一个有趣的行为
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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() |
输出
1 2 | {'l': {...}, 'a': 2} {'l': {...}, 'a': 1} |
并且
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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() |
输出
1 2 3 4 | {'l': {...}, 'a': 2} {'l': {...}, 'a': 2} {'l': {...}, 'a': 2} {'l': {...}} |
显然,
-
如果变量在
exec 中设置且此变量是局部变量,则exec 修改内部字典(由locals() 返回的字典)并且不会将其返回到其原始状态。对locals() 的调用更新了字典(如python文档的第2部分所述),并且忘记了exec 中设置的值。
调用locals() 来更新字典的需要不是python3的错误,因为它已被记录,但它不直观。此外,exec 中的局部变量不会改变函数的局部变量这一事实与python2存在文件差异(文档说"如果你需要在函数后看到代码对本地代码的影响,请传递一个显式的本地字典exec()返回"),我更喜欢python2的行为。 -
如果变量在
exec 中设置且此变量之前不存在,则exec 将修改内部字典,除非之后设置变量。似乎locals() 更新字典的方式存在错误;此错误通过在exec 之后调用locals() 来访问exec 中的值集。
把它们加起来:
Please note:
Ok.
I do not tell anything new here. This is just an assembly of the truth
out there found in all the other answers and comments.
All I try here is to bring light to some of the more obscure details.Ok.
Python 2和Python 3之间的唯一区别是,实际上,
然而,这种烦恼与
请注意,
"在本地范围内引用变量的范围明确的可变单例"是什么意思?
单例的这些更改不会传播回本地范围,因为对象中的所有条目都是
在Python中,字符串和数字不可变。这意味着,如果您为某个条目指定了某些内容,则不会更改该条目所指向的对象,而是引入一个新对象并将该引用分配给该条目。例:
1 2 3 4 5 6 | a = 1 d = locals() d['a'] = 300 # d['a']==300 locals() # d['a']==1 |
除了优化,这样做:
(其中
所以局部变量
For more on this surprising detail, why
1 is a singleton while300 is not, see https://stackoverflow.com/a/306353Ok.
But please do not forget: Numbers are immutable, so if you try to change a number to another value, you effectively create another object.
Ok.
结论:
你无法将Python 2的
但是,您可以将Python 3的行为引入Python 2,这样您今天就可以编写运行相同的程序,无论它们是使用Python 3还是Python 2运行。这是因为在(较新的)Python 2中也可以使用带有参数的函数的
1 | exec"code" |
(仅适用于Python 2)变为(适用于Python 2和3):
1 | exec("code", globals(), locals()) |
但请注意,
最后一句话:
Python 3中
在Python 2中,您无法跨
好。
我恐怕无法完全解释它,但它主要来自于函数内部的b是局部的,并且
试试这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | from sys import version print(version) def execute1(a, st): b = 42 exec("b = {} print('b:', b)".format(st)) print(b) def execute2(a, st): global b b = 42 exec("global b; b = {} print('b:', b)".format(st)) print(b) a = 1. execute1(a,"1.E6*a") print() execute2(a,"1.E6*a") print() b = 42 exec("b = {} print('b:', b)".format('1.E6*a')) print(b) |
哪能给我
1 2 3 4 5 6 7 8 9 10 | 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。
请注意,我认为