python exec 如何与当地人合作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1463306/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does exec work with locals?
提问by ubershmekel
I thought this would print 3, but it prints 1:
我以为这会打印 3,但它会打印 1:
def f():
a = 1
exec("a = 3")
print(a)
回答by Mark Rushakoff
This issue is somewhat discussed in the Python3 bug list. Ultimately, to get this behavior, you need to do:
这个问题在Python3 错误列表中有一些讨论。最终,要获得此行为,您需要执行以下操作:
def foo():
ldict = {}
exec("a=3",globals(),ldict)
a = ldict['a']
print(a)
And if you check the Python3 documentation on exec
, you'll see the following note:
如果您查看 上的 Python3 文档exec
,您将看到以下注释:
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.
默认本地人的行为如
locals()
下面的功能所述:不应尝试修改默认本地人字典。如果您需要在函数 exec() 返回后查看代码对局部变量的影响,请传递一个显式局部变量字典。
That means that one-argument exec
can't safely perform any operations that would bind local variables, including variable assignment, imports, function definitions, class definitions, etc. It can assign to globals if it uses a global
declaration, but not locals.
这意味着单参数exec
不能安全地执行任何绑定局部变量的操作,包括变量赋值、导入、函数定义、类定义等。如果它使用global
声明,它可以赋值给全局变量,但不能赋值给局部变量。
Referring back to a specific message on the bug report, Georg Brandl says:
回顾错误报告中的特定消息,Georg Brandl 说:
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.
动态修改函数的局部变量是不可能的,不会有几个后果:通常,函数局部变量不存储在字典中,而是一个数组,其索引是在编译时根据已知语言环境确定的。这至少与 exec 添加的新本地人发生冲突。旧的 exec 语句绕过了这一点,因为编译器知道如果在函数中发生没有 globals/locals args 的 exec,那么该命名空间将是“未优化的”,即不使用 locals 数组。由于 exec() 现在是一个普通函数,编译器不知道“exec”可能绑定到什么,因此不能特殊对待。
Emphasis is mine.
重点是我的。
So the gist of it is that Python3 can better optimize the use of local variables by notallowing this behavior by default.
所以,它的要点是,Python3可以更好地优化使用局部变量不会允许在默认情况下此行为。
And for the sake of completeness, as mentioned in the comments above, this doeswork as expected in Python 2.X:
为了完整起见,正如上面的评论中提到的,这在 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
回答by Kasramvd
The reason that you can't change local variables within a function using exec
in that way, and why exec
acts the way it does, can be summarized as following:
不能exec
以这种方式更改函数内局部变量的原因,以及为什么exec
这样做,可以总结如下:
exec
is a function that shares its local scope with the scope of the most inner scope in which it's called.- Whenever you define a new object within a function's scope it'll be accessible in its local namespace, i.e. it will modify the
local()
dictionary. When you define a new object inexec
what it does is roughly equivalent to following:
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
is a temporary namespace that resets after each instantiation (each time you call the exec
).
temp
是一个临时命名空间,在每次实例化后重置(每次调用exec
)。
- Python starts looking up for the names from local namespace. It's known as LEGB manner. Python starts from Local namespce then looks into the Enclosing scopes, then Global and at the end it looks up the names within Buit-in namespace.
- Python 开始从本地命名空间中查找名称。它被称为 LEGB 方式。Python 从本地命名空间开始,然后查看封闭作用域,然后是全局,最后它在内置命名空间中查找名称。
A more comprehensive example would be something like following:
更全面的示例如下所示:
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)")
Output:
输出:
{'l_var': 10}
{'l_var': 10}
locals are the same.
当地人是一样的。
{'l_var': 10, 'g_var': 222}
after adding g_var
and changing the l_var
it only adds g_var
and left the l_var
unchanged.
添加g_var
和更改后,l_var
它只会添加g_var
并l_var
保持不变。
{'l_var': 111, 'g_var': 222}
l_var
is changed because we are changing and printing the locals in one instantiation ( one call to exec).
l_var
更改是因为我们在一个实例化(一次调用 exec)中更改和打印本地变量。
{'l_var': 10, 'g_var': 222}
{'l_var': 10, 'g_var': 222}
In both function's locals and exec's local l_var
is unchanged and g_var
is added.
在函数的 locals 和 exec 的 locals 中l_var
都没有改变并g_var
添加。
Inner function:
{}
{'inner_var': 100}
{'inner_var': 100}
inner_function
's local is same as exec's local.
inner_function
的本地与 exec 的本地相同。
['g_var', 'test']
global is only contain g_var
and function name (after excluding the special methods).
global 只是包含g_var
和函数名(排除特殊方法后)。
---------------------
(5, 10)
5
回答by Macabeus
If you are inside a method, you can do so:
如果你在一个方法中,你可以这样做:
class Thing():
def __init__(self):
exec('self.foo = 2')
x = Thing()
print(x.foo)