[英]understand closure in python
我尝试通过以下代码了解闭包
主要
class foo(object):
def __init__(self):
self.a=10
def test(self):
def re():
print self.a
return re
f1=foo()
k1=f1.test()
k1()# output 10
f1.a=20# line A
k1()# output 20
追加case1或case2
情况1:
del f1# line B
k1()# line C output 20
情况2:
del f1.a
k1()# line D .error
从A行来看,似乎k1()的输出取决于f1.a。 如果我删除了f1,则应删除f1.a。 为什么lineC输出20? 。 如果k1()不依赖于f1.a,为什么lineD输出错误? 请帮忙解释一下。 谢谢
说“ k1
取决于f1.a
”并不完全准确。 k1
使用表达式self.a
,而self.a
不是原子单位,而是由一个裸名(self)和一个属性(a)组成。 这些中的任何一个都可以独立失败。 在第二种情况下,只有属性查找失败(即,对象没有属性a
)。
通过执行del f1
,您没有删除对象。 您只删除了名称 f1
。 如果对该对象还有其他引用,则该对象仍然存在。 还有另一个参考,即k1
的闭包。 见这个问题进行更多的解释,但基本上当你调用f1.test()
价值self
该呼叫被“保存”返回的功能(你叫内k1
),因为self
是封闭函数的局部变量test
。 因此, k1
仍然可以访问以前称为f1
的对象,并且调用成功。
在第二种情况下,您从称为f1
的对象中删除了属性a
。 re
不保存对该属性的引用,因为闭包仅保存该封闭函数的局部变量。 当您调用re
,它将尝试查找self.a
,但此操作失败,因为尽管对象存在,但属性不存在。
可能有助于理解差异的一件事:请注意, re
并未使用名称 f1
。 它指的是“ self
这个名字。 在您的设置中,该对象与f1
相同,但该对象指向两个不同的名称。 相反, re
确实使用了属性名称a
,并且在案例2中调用该用法时,用法会失败。
如果re
确实使用了名称f1
,则删除该名称也将失败。 如果将re
更改为print f1.a
而不是print self.a
,则它将寻找名称为f1
的全局变量,如果该变量不存在,则将失败。 在这种情况下,永远不会尝试寻找属性a
,因为该对象最初并不存在。
如果我删除了f1,则应删除f1.a
那是不对的。 如果您del f1
,它将减少f1
对象的引用计数器并将其从本地dict中删除,因此无法访问它。 当参考。 计数器达到0,Python GC将占用的内存返回给OS。
创建访问外部上下文的闭包时,Python会在本地闭包范围内隐式创建对该上下文的引用。 在print self.a
之前添加print(locals())
可以看到k1中引用了foo对象。
因此,当在情况1中使用现有k1
删除f1
时, f1
从模块上下文中消失,但该对象仍然存在,并且在k1
只有一个引用。 因此可以调用k1()
并获得20。
在情况2中del f1.a
时,将从f1
对象的上下文中删除a
。 只有一个对象f1,因此a
既不能从f1.a
也不能从k1
不可访问。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.