def f():
L = []
for i in range(5):
def n():
return i
L.append(n)
return L
L = f()
print(L[0]())
print(L[1]())
print(L[2]())
print(L[3]())
print(L[4]())
以上代码的输出是
4
4
4
4
4
我的问题是:在 L=f()
之后,f
的局部命名空间是否被破坏了?如果是这样,函数 n
中的 i
如何与命名空间中的 i
相关联?如果不是,什么时候销毁本地命名空间?
最佳答案
函数调用中有许多“本地” namespace ,它们使您的示例行为正常。具体来说,函数中的变量分为三类:
- 本地:仅在函数中使用。可能会返回值,但在函数退出时会破坏对本地名称的绑定(bind)。
f
中的L
就是一个例子。 - 单元格:用于函数和一些嵌套范围。每当调用函数时都会重新创建这些名称,但之后会作为嵌套范围中的闭包保留下来。
f
中的i
就是一个例子。 - 自由:未在函数中定义。这些分为两种类型,全局和非全局。全局变量不会放在闭包中。相反,它们是通过函数的
__globals__
属性访问的。当封闭的命名空间消失时,非全局变量将保留在__closure__
属性的单元格中。n
中的i
是非局部自由变量。 - 还有内置名称,但我们不讨论这些。
当您调用f
时,L
和i
是本地名称。当 f
结束时,为 L
创建的对象被传递出函数,但与本地名称 L
的绑定(bind)被销毁。但是,与 i
的绑定(bind)不会被破坏,因为它是一个单元格变量。绑定(bind)存在于 L
的每个元素的 __closure__
属性中。
如果您查看 L[0].__closure__
,您会在其中的一个单元格中找到 i
。 L[1].__closure__
将引用同一单元格,其中也包含 i
。单元格是相同的,因为它来自 f
的相同调用。
当您通过 L
的元素调用 n
时,i
的最后一个值会被打印出来,因为这是单元格绑定(bind)到的值f
退出。
通过将 i
的值绑定(bind)为 n
中的局部变量,您可以获得不同的行为。例如:
def n(i=i):
print(i)
现在 f
中的 i
变成本地的,因为它不再用作 n
中的非本地。在 n
中,i
现在是一个从默认参数获取值的局部变量。创建函数对象时会绑定(bind)默认参数,因此会在创建列表元素时引用 i
的本地值。这与函数运行时在闭包中查找的自由变量形成对比。这个版本的输出将是
0
1
2
3
4
关于python - 什么时候在 python 中销毁本地命名空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69503432/