在 Python 3 中使用 exec'ed 字符串中定义的函数 [英] Using a function defined in an exec'ed string in Python 3

查看:70
本文介绍了在 Python 3 中使用 exec'ed 字符串中定义的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么下面的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 function exec() 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆