繁体   English   中英

了解python中的闭包

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM