Hol*_*ger 38 python exec python-2.7 python-3.x
下面的代码给出了不同的输出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")
Run Code Online (Sandbox Code Playgroud)
Python2 打印:
2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)]
('b:', 1000000.0)
1000000.0
Run Code Online (Sandbox Code Playgroud)
Python3 打印:
3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
b: 1000000.0
42
Run Code Online (Sandbox Code Playgroud)
为什么Python2将函数b内部的变量绑定到execute函数字符串中的exec值,Python3而不执行此操作?我怎样才能实现Python2in 的行为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
Run Code Online (Sandbox Code Playgroud)
比较ids d和locals()shows表明它们是同一个对象.但在这些条件下b应该是一样的d['b'].我的例子有什么问题?
Mar*_*ers 42
execPython 2和exec()Python 3 之间存在很大差异.您将其exec视为一个函数,但它实际上是Python 2中的一个语句.
由于存在这种差异,您无法使用Python 3中的函数范围更改局部变量exec,即使在Python 2中也是如此.甚至不是先前声明的变量.
locals()仅反映一个方向的局部变量.以下从未在2或3中起作用:
def foo():
a = 'spam'
locals()['a'] = 'ham'
print(a) # prints 'spam'
Run Code Online (Sandbox Code Playgroud)
在Python 2中,使用该exec语句意味着编译器知道关闭本地范围优化(例如,切换LOAD_FAST到LOAD_NAME在本地和全局范围内查找变量).随着exec()作为一个功能,该选项不再可用,现在功能作用域总是优化.
此外,在Python 2中,exec语句显式地将所有locals()返回的函数复制到函数本地使用PyFrame_LocalsToFast,但前提是没有提供全局和局部参数.
正确的解决方法是为您的exec()调用使用新的命名空间(字典):
def execute(a, st):
namespace = {}
exec("b = {}\nprint('b:', b)".format(st), namespace)
print(namespace['b'])
Run Code Online (Sandbox Code Playgroud)
该exec()文件是有关此限制很明确的:
注意:默认的locals的作用如下所述
locals():不应尝试修改默认的locals字典.如果需要在函数返回后查看本地代码的效果,则传递显式的本地字典exec().
我会说这是python3的一个bug.
def u():
exec("a=2")
print(locals()['a'])
u()
Run Code Online (Sandbox Code Playgroud)
打印"2".
def u():
exec("a=2")
a=2
print(a)
u()
Run Code Online (Sandbox Code Playgroud)
打印"2".
但
def u():
exec("a=2")
print(locals()['a'])
a=2
u()
Run Code Online (Sandbox Code Playgroud)
失败了
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in u
KeyError: 'a'
Run Code Online (Sandbox Code Playgroud)
---编辑---另一个有趣的行为:
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()
Run Code Online (Sandbox Code Playgroud)
输出
{'l': {...}, 'a': 2}
{'l': {...}, 'a': 1}
Run Code Online (Sandbox Code Playgroud)
并且
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()
Run Code Online (Sandbox Code Playgroud)
输出
{'l': {...}, 'a': 2}
{'l': {...}, 'a': 2}
{'l': {...}, 'a': 2}
{'l': {...}}
Run Code Online (Sandbox Code Playgroud)
显然,exec当地人的行动如下:
exec并且此变量是局部变量,则exec修改内部字典(返回的字典locals())并且不将其返回到其原始状态.locals()更新字典的调用(如python文档的第2部分所述)和exec忘记的值设置.调用locals()更新字典的需要不是python3的错误,因为它已被记录,但它不直观.此外,内部的exec局部变量不会改变函数的局部性这一事实是与python2的文档差异(文档说"如果你需要在函数exec()之后看到代码对本地的影响,请传递一个显式的本地字典返回"),我更喜欢python2的行为.exec且此变量之前不存在,则exec修改内部字典,除非之后设置变量.似乎locals()更新字典的方式存在错误; 这个bug可以访问内设置的值exec通过调用locals()之后exec.| 归档时间: |
|
| 查看次数: |
29220 次 |
| 最近记录: |