我以为这会打印 3,但它打印 1:
# Python3
def f():
a = 1
exec("a = 3")
print(a)
f()
# 1 Expected 3
这个问题在 Python3 bug 列表 中有所讨论。 最终,要获得这种行为,您需要执行以下操作:
def foo():
ldict = {}
exec("a=3",globals(),ldict)
a = ldict['a']
print(a)
如果您查看 exec
默认局部变量的行为如下函数这意味着单参数
locals()
所述:不应尝试修改默认局部变量字典。如果您需要在函数 exec() 返回后查看代码对局部变量的影响,请传递显式局部变量字典。
exec
无法安全地执行任何绑定局部变量的操作,包括变量赋值、导入、函数定义、类定义等。如果它使用
global
声明,它可以分配给全局变量,但不是当地人。回顾
错误报告中的具体消息,Georg Brandl 说:
动态修改函数的局部变量不是 可能没有几个后果:重点是我的。通常,函数局部变量不是 存储在字典中,而是一个数组,其索引确定于 从已知语言环境编译时间。 这至少与新的冲突 由 exec 添加的当地人。 旧的 exec 语句规避了这一点,因为 编译器知道如果发生没有全局/局部参数的执行 在函数中,该名称空间将是“未优化的”,即不使用 当地人数组。 由于 exec() 现在是一个普通函数,编译器不会 不知道“exec”可能绑定到什么,因此不能治疗 特别.
所以要点是,Python3 可以通过默认情况下
不允许这种行为来更好地优化局部变量的使用。
为了完整起见,正如上面评论中提到的,这确实在Python 2.X中按预期工作:
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def f():
... a = 1
... exec "a=3"
... print a
...
>>> f()
3
exec
更改函数内的局部变量的原因,以及
exec
为何如此行事,可以总结如下:
exec
是一个函数,它与调用它的最内部作用域的作用域共享其局部作用域。
local()
字典。当您在
exec
中定义一个新对象时,它的作用大致相当于以下内容:
from copy import copy
class exec_type:
def __init__(self, *args, **kwargs):
# default initializations
# ...
self.temp = copy(locals())
def __setitem__(self, key, value):
if var not in locals():
set_local(key, value)
self.temp[key] = value
temp
是一个临时命名空间,每次实例化后都会重置(每次调用
exec
时)。
g_var = 5
def test():
l_var = 10
print(locals())
exec("print(locals())")
exec("g_var = 222")
exec("l_var = 111")
exec("print(locals())")
exec("l_var = 111; print(locals())")
exec("print(locals())")
print(locals())
def inner():
exec("print(locals())")
exec("inner_var = 100")
exec("print(locals())")
exec("print([i for i in globals() if '__' not in i])")
print("Inner function: ")
inner()
print("-------" * 3)
return (g_var, l_var)
print(test())
exec("print(g_var)")
输出:
{'l_var': 10}
{'l_var': 10}
当地人都一样。
{'l_var': 10, 'g_var': 222}
添加
g_var
并更改
l_var
后,它仅添加
g_var
并保持
l_var
不变。
{'l_var': 111, 'g_var': 222}
l_var
已更改,因为我们正在一次实例化中更改和打印本地变量(一次调用 exec)。
{'l_var': 10, 'g_var': 222}
{'l_var': 10, 'g_var': 222}
在函数的局部变量和 exec 的局部变量中,
l_var
保持不变,并添加了
g_var
。
Inner function:
{}
{'inner_var': 100}
{'inner_var': 100}
inner_function
的本地与exec的本地相同。
['g_var', 'test']
global 仅包含
g_var
和函数名(排除特殊方法后)。
---------------------
(5, 10)
5