在 Python 3 中使用 exec'ed 字符串中定义的函数 [英] Using a function defined in an exec'ed string in Python 3
问题描述
为什么下面的python3代码会报错?
a='''定义 x():打印(42)'''课堂测试:def __init__(self):执行(一)X()t = 测试()
此消息中的结果:
回溯(最近一次调用):文件bug.py",第 11 行,在 <module> 中t = 测试()文件bug.py",第 9 行,在 __init__ 中X()NameError: 全局名称 'x' 未定义
注意:exec
在 Python 2.x 中只是一个 Simple 语句,而在 Python 3.x 中它是一个函数.
Python 2.7
让我们检查通过执行 a
所做的更改.
类测试:def __init__(self):l, g = locals().copy(), globals().copy()exec a # 不是函数调用而是语句打印 locals() == l, globals() == gX()t = 测试()
输出
假真42
这意味着,它改变了locals
字典中的某些内容.如果在exec
之前和之后打印locals().keys()
,你会看到x
,在exec
之后>.根据 exex 的文档,
在所有情况下,如果省略可选部分,代码将在当前范围内执行.
因此,它完全符合文档中的说明.
Python 3.x:
当我们在 Python 3.x 中执行相同的操作时,我们得到了类似的结果,只是我们得到了那个错误.
类测试:def __init__(self):l, g = locals().copy(), globals().copy()exec(a) # 函数调用,不是语句打印(locals() == l, globals() == g)X()
输出
假真NameError: 名称 'x' 未定义
即使 exec
函数的文档 也说,><块引用>
在所有情况下,如果省略可选部分,代码将在当前范围内执行.
但它在底部还包括一个注释,
<块引用>注意:默认本地变量的行为与下面函数 locals()
的描述相同:不应尝试修改默认本地变量字典.如果您需要在函数 exec()
返回后查看代码对局部变量的影响,请传递一个显式局部变量字典.
所以,我们好奇地查看了locals()
文档并找到
注意:本词典内容不得修改;更改可能不会影响解释器使用的局部变量和自由变量的值.
因此,解释器不接受对 locals()
对象所做的更改.这就是为什么它不能识别本地范围中定义的 x
.
但是当我们这样做时
def __init__(self):exec(a, globals())X()
它有效,因为我们将它添加到 globals
字典中.Python 尝试首先在局部范围内查找 x
,然后在类范围内查找,然后在全局范围内查找,并在那里找到它.所以它执行它没有任何问题.
Why does the following python3 code produces an error?
a='''
def x():
print(42)
'''
class Test:
def __init__(self):
exec(a)
x()
t = Test()
Results in this message:
Traceback (most recent call last):
File "bug.py", line 11, in <module>
t = Test()
File "bug.py", line 9, in __init__
x()
NameError: global name 'x' is not defined
Note: exec
was just a Simple statement in Python 2.x, whereas it is a function in Python 3.x.
Python 2.7
Let us check the changes made by executing a
.
class Test:
def __init__(self):
l, g = locals().copy(), globals().copy()
exec a # NOT a function call but a statement
print locals() == l, globals() == g
x()
t = Test()
Output
False True
42
It means that, it has changed something in the locals
dictionary. If you print locals().keys()
before and after the exec
, you will see x
, after exec
. As per the documentation of exex,
In all cases, if the optional parts are omitted, the code is executed in the current scope.
So, it does exactly what the documentation says.
Python 3.x:
When we execute the same in Python 3.x, we get similar result, except we get that error.
class Test:
def __init__(self):
l, g = locals().copy(), globals().copy()
exec(a) # Function call, NOT a statement
print(locals() == l, globals() == g)
x()
Output
False True
NameError: name 'x' is not defined
Even the documentation of exec
function says,
In all cases, if the optional parts are omitted, the code is executed in the current scope.
But it also includes a note at the bottom,
Note: 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 functionexec()
returns.
So, we curiously check the locals()
documentation and find
Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
So, interpreter doesn't honor the changes made to the locals()
object. That is why it is not recognizing x
as defined in the local scope.
But when we do
def __init__(self):
exec(a, globals())
x()
it works, because we add it to the globals
dictionary. Python tries to find x
in local scope first and then in class scope and then in global scope and it finds it there. So it executes it without any problem.
这篇关于在 Python 3 中使用 exec'ed 字符串中定义的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!