Python 2和Python 3中的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函数中的variablesb绑定到exec函数string中的值,而Python3不这样做? 我如何在Python3实现Python2的行为? 我已经尝试将globals和locals的字典传递给Python3 exec函数,但目前为止还没有任何工作。

—编辑—

在阅读Martijns的答案后,我进一步用Python3分析了这个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来更改函数范围中的局部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是不提供全局variablesPyFrame_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()函数内声明它。 但我发现这是行不通的(这是我无法解释的部分)。