我认为这会打印3,但它打印1:
def f():
a = 1
exec("a = 3")
print(a)
答案 0 :(得分:36)
Python3 bug list对此问题进行了详细讨论。最终,要获得此行为,您需要执行以下操作:
def foo():
ldict = {}
exec("a=3",globals(),ldict)
a = ldict['a']
print(a)
如果您选中the Python3 documentation on exec
,则会看到以下注释:
默认的locals的行为如下面的函数
locals()
所述:不应尝试修改默认的locals字典。如果您需要在函数exec()返回后查看代码对locals的影响,则传递显式的locals字典。
回到a specific message on the bug report,Georg Brandl说:
要动态修改函数的局部变量不是 可能没有几个后果:通常,函数本地人不是 存储在字典中,但是数组,其索引的确定位置为 从已知语言环境编译时间。这至少与新的碰撞 本地人由exec添加。旧的执行声明绕过了这个,因为 编译器知道如果没有globals / locals的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
答案 1 :(得分:2)
如果你在某个方法中,你可以这样做:
class Thing():
def __init__(self):
exec('self.foo = 2')
x = Thing()
print(x.foo)
答案 2 :(得分:1)
您无法以这种方式使用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