How does exec work with locals?
我以为这会印3,但印1:
1 2 3 4 | def f(): a = 1 exec("a = 3") print(a) |
这个问题在python3 bug列表中有点讨论。最终,要获得这种行为,您需要执行以下操作:
1 2 3 4 5 | def foo(): ldict = {} exec("a=3",globals(),ldict) a = ldict['a'] print(a) |
如果您查看
The default locals act as described for function
locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.
在引用bug报告中的特定消息时,GeorgBrandl说:
To modify the locals of a function on the fly is not
possible without several consequences: normally, function locals are not
stored in a dictionary, but an array, whose indices are determined at
compile time from the known locales. This collides at least with new
locals added by exec. The old exec statement circumvented this, because
the compiler knew that if an exec without globals/locals args occurred
in a function, that namespace would be"unoptimized", i.e. not using the
locals array. Since exec() is now a normal function, the compiler does
not know what"exec" may be bound to, and therefore can not treat is
specially.
重点是我的。
因此,其要点是python3可以通过在默认情况下不允许这种行为来更好地优化局部变量的使用。
为了完整起见,正如上面的注释中所提到的,这在python 2.x中是可以正常工作的:
1 2 3 4 5 6 7 8 9 10 | 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 3 4 5 6 | class Thing(): def __init__(self): exec('self.foo = 2') x = Thing() print(x.foo) |
你可以在这里了解更多
使用
1 2 3 4 5 6 7 8 9 10 11 | 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 |
更全面的例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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)") |
输出:
1 2 | {'l_var': 10} {'l_var': 10} |
当地人也一样。
1 | {'l_var': 10, 'g_var': 222} |
添加
1 | {'l_var': 111, 'g_var': 222} |
由于我们在一个实例(一个对exec的调用)中更改并打印局部变量,因此
1 2 | {'l_var': 10, 'g_var': 222} {'l_var': 10, 'g_var': 222} |
在这两个函数中,local s和exec的local
1 2 3 4 | Inner function: {} {'inner_var': 100} {'inner_var': 100} |
1 | ['g_var', 'test'] |
全局只包含
1 2 3 4 | --------------------- (5, 10) 5 |