Python 弱引用 学习

参考
1.weakref – Garbage-collectable references to objects
2.Python弱引用介绍
和许多其它的高级语言一样,Python使用了垃圾回收器来自动销毁那些不再使用的对象。每个对象都有一个引用计数,当这个引用计数为0时Python能够安全地销毁这个对象。

引用计数会记录给定对象的引用个数,并在引用个数为零时收集该对象。由于一次仅能有一个对象被回收,引用计数无法回收循环引用的对象。

一组相互引用的对象若没有被其它对象直接引用,并且不可访问,则会永久存活下来。一个应用程序如果持续地产生这种不可访问的对象群组,就会发生内存泄漏。

在对象群组内部使用弱引用(即不会在引用计数中被计数的引用)有时能避免出现引用环,因此弱引用可用于解决循环引用的问题。

在计算机程序设计中,弱引用,与强引用相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。一个对象若只被弱引用所引用,则可能在任何时刻被回收。弱引用的主要作用就是减少循环引用,减少内存中不必要的对象存在的数量。

使用weakref模块,你可以创建到对象的弱引用,Python在对象的引用计数为0或只存在对象的弱引用时将回收这个对象。

创建弱引用

你可以通过调用weakref模块的ref(obj[,callback])来创建一个弱引用,obj是你想弱引用的对象,callback是一个可选的函数,当因没有引用导致Python要销毁这个对象时调用。回调函数callback要求单个参数(弱引用的对象)。

一旦你有了一个对象的弱引用,你就能通过调用弱引用来获取被弱引用的对象。

1234567891011121314151617181920212223 >>>> import sys>>> import weakref>>> class Man:  def __init__(self,name):    print self.name = name    >>> o = Man(\’Jim\’)>>> sys.getrefcount(o)   2>>> r = weakref.ref(o) # 创建一个弱引用>>> sys.getrefcount(o) # 引用计数并没有改变2>>> r<weakref at 00D3B3F0; to \’instance\’ at 00D37A30> # 弱引用所指向的对象信息>>> o2 = r() # 获取弱引用所指向的对象>>> o is o2True>>> sys.getrefcount(o)3>>> o = None>>> o2 = None>>> r # 当对象引用计数为零时,弱引用失效。<weakref at 00D3B3F0; dead>de>

上面的代码中,我们使用sys包中的getrefcount()来查看某个对象的引用计数。需要注意的是,当使用某个引用作为参数,传递给getrefcount()时,参数实际上创建了一个临时的引用。因此,getrefcount()所得到的结果,会比期望的多1。

一旦没有了对这个对象的其它的引用,调用弱引用将返回None,因为Python已经销毁了这个对象。 注意:大部分的对象不能通过弱引用来访问。

weakref模块中的getweakrefcount(obj)和getweakrefs(obj)分别返回弱引用数和关于所给对象的引用列表。

弱引用对于创建对象(这些对象很费资源)的缓存是有用的。

创建代理对象

代理对象是弱引用对象,它们的行为就像它们所引用的对象,这就便于你不必首先调用弱引用来访问背后的对象。通过weakref模块的proxy(obj[,callback])函数来创建代理对象。使用代理对象就如同使用对象本身一样:

123456789101112 import weakrefclass Man: def __init__(self, name):       self.name = name def callback(self): print \”callback\” o = Man(\’Jim\’)p = weakref.proxy(o, callback)p.test()o = None

callback参数的目的和ref函数相同。在Python删除了一个引用的对象之后,使用代理将会导致一个weakref.ReferenceError错误。

循环引用

前面说过,使用弱引用,可以解决循环引用不能被垃圾回收的问题。
首先我们看下常规的循环引用,先创建一个简单的Graph类,然后创建三个Graph实例:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 # -*- coding:utf-8 -*-import weakrefimport gcfrom pprint import pprint  class Graph(object):    def __init__(self, name):        self.name = name        self.other = None     def set_next(self, other):        print \”%s.set_next(%r)\” %f, other):        print \”%s.set_next(%r)\” %