【问题标题】:Python eval does not use locals() where called from nor locals() passed to eval for funcPython eval 不使用 locals() 调用的地方,也不使用 locals() 传递给 eval 的 func
【发布时间】:2017-04-03 21:26:11
【问题描述】:
def one():
    var1 = 1

    def sub():
        nonlocal var1
        var1 += 1
        return var1

    return sub


def two():
    var1 = 5
    sub1 = one()
    return eval('sub1()', globals(), locals())


if __name__ == "__main__":
    print(two())

我原以为上面的代码会打印 6,但它会打印 2。Python 3.6.1 文档状态:“表达式参数被解析并评估为 Python 表达式(从技术上讲,是条件列表),使用全局变量和局部变量字典作为全局和本地命名空间。"

全局和局部命名空间是否只适用于 eval 中可以解析的内容?函数调用 sub1() 是在 sub1() 函数的命名空间中求值的,而不管传递给 eval 的是全局还是局部?

【问题讨论】:

  • 所以您期望sub 中的nonlocal 指的是two 的本地范围,而不是one 的本地范围? sub 的闭包在传递给 eval 之前已经设置为包含 1

标签: python eval


【解决方案1】:

是的,全局和本地命名空间几乎只适用于那些可以在eval 中解析的命名空间。函数对象静态绑定到它们的全局对象(模块!),当输入函数时,会创建一个新的局部命名空间。

【讨论】:

    【解决方案2】:

    nonlocal 指的是函数定义的父范围,而不是调用站点。当您将局部变量传递给eval 时,您并没有更改您调用的函数内部的局部变量——您正在为正在评估的代码 sn-p 设置局部变量。所以写eval('sub1()', globals(), locals() 等同于写sub1(),因为无论哪种方式,相同的局部变量都在作用域内——如果你这样写,你不会期望 sub1 返回 6,对吗?

    【讨论】:

    • Python 中编译时的链接是否发生了变化?你的评论很有道理,但我记得上次我在 python 2 中使用 eval 时更有用。
    • @Buoy:Python 2 甚至没有非本地的,所以我认为无论你在想什么情况,你可能一直在做一些完全不同的事情。但是最接近的等价物,reading 从函数的父作用域中读取一个变量,在 2 和 3 之间没有变化(您可以通过将代码更改为具有 def sub(): return var1 + 1 并在 Python 2 中运行它来看到这一点) .这基本上就是词法作用域的工作原理——在 OP print 6 中包含代码意味着动态作用域,而我所知道的任何 Python 版本都没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-24
    • 2013-10-04
    • 1970-01-01
    • 2014-02-01
    • 2011-06-27
    • 1970-01-01
    • 2023-03-28
    相关资源
    最近更新 更多