Python 访问简单命名空间的封闭范围中的变量

Python 访问简单命名空间的封闭范围中的变量,python,Python,在Python中,函数可以访问封闭范围内的变量 为了测试其范围/一致性,我做了一个创建简单名称空间的实验,但没有得到预期的行为。我不明白为什么这个简单的案例应该被区别对待,有一个好的解释吗 下面是一个简单的例子: import types bunch = types.SimpleNamespace( x = 5, y = 12, printx = lambda: print(x) ) 运行上述代码后执行bunch.printx()将导致NameError,因为没有定义x

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

为了测试其范围/一致性,我做了一个创建简单名称空间的实验,但没有得到预期的行为。我不明白为什么这个简单的案例应该被区别对待,有一个好的解释吗

下面是一个简单的例子:

import types
bunch = types.SimpleNamespace(
    x = 5,
    y = 12,
    printx = lambda: print(x)
)
运行上述代码后执行bunch.printx()将导致NameError,因为没有定义x。但是我们已经定义了一个函数“printx”,它被bunch名称空间所包围,但是该函数不能访问封闭名称空间中的变量

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

import bunch
bunch.printx()
bunch.py:

x = 5,
y = 12,
printx = lambda: print(x)
运行以下代码将导致按预期打印5:

import bunch
bunch.printx()
我确实发现了这个问题,这可能与:
我在这里提供的示例对于访问封闭范围内的变量更为明确。

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”定义的,而不是定义lambda时“x”所具有的值。

您的
lambda
的封闭上下文是整个模块;它当然没有包含在
bunch
名称空间中,因为它甚至还不存在(而且也不是一个语法构造,所以它实际上不能“包含”任何内容)。@jasonharper但是当我导入该模块时,它确实被加载到bunch名称空间中。但是在第一种情况下,我显式地创建了名称空间。具体地说,我很困惑为什么第一个案例不能访问封闭名称空间中的变量,您理解为什么吗?lambda不知道也不可能知道关于一个尚不存在的名称空间的任何信息。函数的封闭范围是在编译时完全确定的静态属性。明白了,谢谢。回答这个问题。谢谢,我想我明白了。如果我将打印lambda更改为执行打印(bunch.x),则确认没有错误。因此,在我的第一个示例中,lambda被定义为从全局范围打印x,而不是从bunch命名空间中的范围打印x。稍后执行此函数将被简单地解释为print(x),即全局x,而没有全局x。然而,在第二种情况下,我执行导入操作,因为导入必须将所有定义映射到bunch名称空间中,而在第一种情况下,我必须显式地执行(print(bunch.x))。我遵循的是否准确?如果我遵循的是正确的,那么是的,在第二种情况下,bunch.printx()在bunch名称空间中“存在”,因此他将首先在那里搜索,然后再查找全局x“更高”的位置。