Gre*_*war 20 python python-3.x python-internals
为什么以下python3代码会产生错误?
a='''
def x():
print(42)
'''
class Test:
def __init__(self):
exec(a)
x()
t = Test()
Run Code Online (Sandbox Code Playgroud)
结果在此消息中:
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
Run Code Online (Sandbox Code Playgroud)
the*_*eye 16
注意:exec
它只是Python 2.x中的一个Simple语句,而它是Python 3.x中的一个函数.
让我们检查执行所做的更改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()
Run Code Online (Sandbox Code Playgroud)
产量
False True
42
Run Code Online (Sandbox Code Playgroud)
这意味着,它改变了locals
字典中的内容.如果您locals().keys()
在之前和之后打印exec
,您将看到x
之后exec
.根据exex的文档,
在所有情况下,如果省略可选部分,则代码在当前范围内执行.
因此,它完全符合文档所说的内容.
当我们在Python 3.x中执行相同的操作时,除了得到错误之外,我们得到类似的结果.
class Test:
def __init__(self):
l, g = locals().copy(), globals().copy()
exec(a) # Function call, NOT a statement
print(locals() == l, globals() == g)
x()
Run Code Online (Sandbox Code Playgroud)
产量
False True
NameError: name 'x' is not defined
Run Code Online (Sandbox Code Playgroud)
在所有情况下,如果省略可选部分,则代码在当前范围内执行.
但它还包括一个底部的注释,
注意:默认的locals的作用如下所述
locals()
:不应尝试修改默认的locals字典.如果需要在函数exec()
返回后查看本地代码的效果,则传递显式的本地字典.
所以,我们好奇地检查locals()
文档并找到
注意:不应修改此词典的内容; 更改可能不会影响解释器使用的本地和自由变量的值.
因此,解释器不尊重locals()
对象所做的更改.这就是为什么它不承认x
在本地范围内的定义.
但是当我们做的时候
def __init__(self):
exec(a, globals())
x()
Run Code Online (Sandbox Code Playgroud)
它有效,因为我们将它添加到globals
字典中.Python首先尝试x
在本地范围内查找,然后在类范围内查找,然后在全局范围内查找,并在那里找到它.所以它执行它没有任何问题.
我假设你使用的是Python3.x,因为在Python2.7中,你的代码对我来说很好.因此,对于Python3.x,请更改该行
exec(a)
Run Code Online (Sandbox Code Playgroud)
至
exec(a, globals())
Run Code Online (Sandbox Code Playgroud)
为了添加x
到全局命名空间.
Python3 exec
也需要globals
和locals
映射类型,它作为对于给定的代码执行的上下文的可选参数:
exec(object[, globals[, locals]])
Run Code Online (Sandbox Code Playgroud)
默认情况下,本地范围将传入两者.执行的代码可以使用它,也可以修改dict,但它对实际的本地范围没有影响.参见locals()
和示例:
a = '''
print(t)
def x():
print(42)
'''
class Test:
def __init__(self):
t = 'locals are accessible'
# same as calling exec(a, locals())
exec(a)
print(locals())
x()
t = Test()
Run Code Online (Sandbox Code Playgroud)
输出:
locals are accessible
{'x': <function x at 0x6ffffd09af0>,
'self': <__main__.Test object at 0x6ffffce3f90>,
't': 'locals are accessible'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 13, in __init__
NameError: global name 'x' is not defined
Run Code Online (Sandbox Code Playgroud)
如果您希望在调用x
后可用,则exec
需要传入全局或自定义范围:
# global scope
class Test:
def __init__(self):
exec(a, globals())
x()
# custom scope
class Test:
def __init__(self):
scope = {}
exec(a, scope)
scope['x']()
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
9197 次 |
最近记录: |