以下代码在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
将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
locals()
和b
的ID比较表明它们是同一个对象。但在这些情况下,d['b']
应与{{1}}相同。我的例子有什么问题?
答案 0 :(得分:39)
Python 2中的exec
和Python 3中的exec()
之间存在很大差异。您将exec
视为一个函数,但它确实是一个语句在Python 2中。
由于存在这种差异,您无法使用exec
在Python 3中更改函数范围中的局部变量,即使它在Python 2中是可能的。甚至不是先前声明的变量。
locals()
仅反映一个方向的局部变量。以下从未在2或3中起作用:
def foo():
a = 'spam'
locals()['a'] = 'ham'
print(a) # prints 'spam'
在Python 2中,使用exec
语句意味着编译器知道关闭本地范围优化(例如从LOAD_FAST
切换到LOAD_NAME
,以查找两者中的变量本地和全球范围)。当exec()
是一个函数时,该选项不再可用,函数范围现在始终优化。
此外,在Python 2中,exec
语句使用locals()
将PyFrame_LocalsToFast
中找到的所有变量显式复制回函数本地,但前提是没有全局和 locals 参数。
正确的解决方法是为exec()
电话使用新的命名空间(字典):
def execute(a, st):
namespace = {}
exec("b = {}\nprint('b:', b)".format(st), namespace)
print(namespace['b'])
exec()
documentation对此限制非常明确:
注意:默认 locals 的行为与下面的函数
locals()
相同:对默认 locals 字典的修改不应该是尝试。如果您需要在函数exec()
返回后查看代码对本地的影响,请传递显式的 locals 字典。
答案 1 :(得分:5)
我说这是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
内设置变量并且此变量是局部变量,则exec
修改内部字典(由locals()
返回的字典)并且不会将其返回到原始状态。对locals()
的调用更新了字典(如python文档的第2部分所述),忘记了exec
中的值集。
调用locals()
来更新字典的需要不是python3的错误,因为它已被记录,但它不直观。此外,exec
内的本地修改不会改变函数的局部性这一事实是与python2的文档差异(文档说“如果您需要查看代码对本地代码的影响,请传递显式本地字典在函数exec()返回“)之后,我更喜欢python2的行为。exec
内设置且此变量之前不存在,则exec
将修改内部字典,除非之后设置变量。似乎locals()
更新字典的方式存在错误;通过exec
之后调用locals()
,此错误可以访问exec
中的值集。答案 2 :(得分:2)
总结一下:
exec
的不同行为源于exec
是Python 2中的一个语句,而它在Python 3中成为一个函数。请注意:
我在这里没有说新的东西。这只是一个事实的集合 在那里找到所有其他答案和评论。 我在这里尝试的只是为一些更加模糊的细节带来光明。
Python 2和Python 3之间的唯一区别是,实际上,exec
能够在Python 2中更改封闭函数的本地范围(因为它是一个语句并且可以访问当前的本地范围)并且不能再在Python 3中执行此操作(因为它现在是一个函数,因此在它自己的本地范围内运行)。
然而,这种烦恼与exec
陈述无关,它只是源于一个特殊的行为细节:
locals()
返回一些我想调用的东西&#34;一个范围明确的可变单例,在调用locals()
之后,总是只引用本地范围内的所有变量&#34;
请注意locals()
的行为在Python 2和3之间没有变化。因此,这种行为以及exec
如何工作的变化看起来像是不稳定,但不是,因为它只是暴露了一些细节,总是在那里。
&#34;范围明确的可变单例引用局部范围内的变量&#34;意思?
scope-wise singleton
,因为无论您在同一范围内调用locals()
的频率如何,返回的对象始终是相同的。
id(d) == id(locals())
,因为d
和locals()
指的是同一个对象,同一个单身,因为只能有一个(在不同的范围内你得到一个不同的对象,但在相同的范围内,你只能看到这一个。)mutable
,因为它是普通对象,所以你可以改变它。
locals()
强制对象中的所有条目再次引用本地范围中的变量。d
),则会更改该对象,因为它是一个普通的可变对象。单例的这些更改不会传播回本地作用域,因为对象中的所有条目都是references to the variables in the local scope
。因此,如果您更改条目,这些更改单例对象,而不是更改引用之前引用指向的位置的内容&#34; (因此你不要改变局部变量)。
在Python中,字符串和数字不可变。这意味着,如果您为某个条目指定了某些内容,则不会更改该条目所指向的对象,而是引入一个新对象并将该引用分配给该条目。例如:
a = 1
d = locals()
d['a'] = 300
# d['a']==300
locals()
# d['a']==1
除了优化之外,还可以:
LOCALS['a']
中
(其中LOCALS
应为内部本地范围)SINGLETON
对象SINGLETON
,因此它会引用LOCALS
SINGLETON
的指针存储到LOCALS['d']
d['a']
SINGLETON
也会更新。LOCALS
未更新,
所以局部变量a
或LOCALS['a']
仍然是数字(1)locals()
,SINGLETON
已更新。d
引用SINGLETON
,而非LOCALS
,d
也会发生变化!有关这个令人惊讶的细节的更多信息,为什么
1
是单身而300
不是,请参阅https://stackoverflow.com/a/306353但请不要忘记:数字是不可变的,因此如果您尝试将数字更改为其他值,则可以有效地创建另一个对象。
结论:
你无法将Python 2的exec
行为恢复到Python 3(除非通过更改代码),因为无法再改变程序流之外的局部变量。
但是,您可以将Python 3的行为引入Python 2,这样您今天就可以编写运行相同的程序,无论它们是使用Python 3还是Python 2运行。这是因为在(较新的) Python 2你可以使用exec
函数和参数(事实上,那些是2或3元组),允许使用相同的语法和Python 3中已知的相同语义:
exec "code"
(仅适用于Python 2)变为(适用于Python 2和3):
exec("code", globals(), locals())
但请注意,"code"
不能再以这种方式改变本地封闭范围。另请参阅https://docs.python.org/2/reference/simple_stmts.html#exec
最后一句话:
Python 3中exec
的更改很好。因为优化。
在Python 2中,您无法在exec
之间进行优化,因为包含不可变内容的所有局部变量的状态可能会无法预测地发生变化。这不可能再发生了。现在,函数调用的通常规则同样适用于exec()
所有其他函数。
答案 3 :(得分:1)
我担心我无法完全解释它,但它主要来自于函数内部的b是本地的,并且exec()
似乎分配给全局b。您必须在exec语句中的函数和中声明b是全局的。
试试这个:
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()
函数中声明它。但我觉得这不起作用(这是我无法解释的部分)。