【问题标题】:Access to Variables in Enclosing Scope for Simple Namespace访问简单命名空间的封闭范围内的变量
【发布时间】:2018-11-25 13:46:48
【问题描述】:

在 Python 中,函数可以访问封闭范围内的变量。

作为对此范围/一致性的测试,我做了一个创建简单命名空间的实验,但没有得到预期的行为。我不明白为什么要区别对待这种简单的情况,有好的解释吗?

这是一个简单的例子:

import types
bunch = types.SimpleNamespace(
    x = 5,
    y = 12,
    printx = lambda: print(x)
)

在运行上述代码后执行 bundle.printx() 将导致 NameError 因为 x 未定义。但是我们已经定义了一个被包命名空间包围的函数“printx”,但是该函数没有访问封闭命名空间中的变量的权限。

相比之下,将代码 bundle.py 作为外部文件导入会将对象放置在 bundle 命名空间中,并且可以按预期访问封闭命名空间中的变量:

bunch.py​​:

x = 5,
y = 12,
printx = lambda: print(x)

运行以下代码将按预期打印 5:

import bunch
bunch.printx()

我确实找到了这个问题,可能与此有关:Python: Access from within a lambda a name that's in the scope but not in the namespace 我在此处提供的示例更清楚地特定于访问封闭范围内的变量。

【问题讨论】:

  • 您的lambda 的封闭上下文是整个模块;它当然没有包含在 bunch 命名空间中,因为它甚至还不存在(而且它也不是一个语法结构,所以它实际上不能“包含”任何东西)。
  • @jasonharper 但是当我导入该模块时,它确实被加载到了束命名空间中。但在第一种情况下,我显式地创建了命名空间。具体来说,我很困惑为什么第一种情况无法访问封闭命名空间中的变量,你明白为什么吗?
  • lambda 不知道也不知道关于尚不存在的命名空间的任何信息。函数的封闭范围是一个静态属性,完全在编译时确定。
  • 知道了,谢谢。
  • stackoverflow.com/questions/18184357/… 回答了这个问题。

标签: python


【解决方案1】:

python 中的每个函数对象都有 3 个属性:

  • 常量
  • 当地人
  • 全局变量

局部变量在函数内部定义,全局变量在函数外部定义。查看您尝试执行的字节码:

dis.dis(bunch.printx)
  6           0 LOAD_GLOBAL              0 (print)
              2 LOAD_GLOBAL              1 (x)
              4 CALL_FUNCTION            1
              6 RETURN_VALUE

您正在尝试在全局范围内查找变量“x”。在您执行函数的命名空间中,没有这样的全局变量。
lambda 是用全局变量“x”定义的,而不是“x”在定义 lambda 期间的值。

【讨论】:

  • 谢谢你,我想我跟着。如果我将 print lambda 更改为执行 print(bunch.x) ,则确认这一点没有错误。因此,在我的第一个示例中,lambda 被定义为从全局范围打印 x,而不是在 bundle 命名空间内的范围。稍后执行此函数被简单地解释为 print(x),即全局 x,它没有。然而,在第二种情况下,我进行导入工作,因为导入必须将所有定义映射到束命名空间内,而在第一种情况下,我必须明确地这样做(print(bunch.x))。我是否准确地遵循了这一点?
  • 如果我正确地跟随了你,那么是的,在第二种情况下,bundle.printx() 'lives' 在 bundle 命名空间中,因此他会先在那里搜索,然后再寻找全局 x 'higher'起来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
  • 2018-06-29
  • 2017-01-24
相关资源
最近更新 更多