weakref
weakref — Weak references
2.1版本中的新功能。
源代码:
Lib / weakref.py
该weakref
模块允许Python程序员创建对象的弱引用
。
在下文中,术语指代
对象是指由弱参考引用的对象。
对对象的弱引用不足以使对象保持活动状态:当对引用的唯一剩余引用是弱引用时,垃圾收集可以自由地销毁指示对象并将其内存用于其他事情。弱引用的主要用途是实现缓存或映射,以保存大对象,因为希望大对象不会因为它出现在缓存或映射中而保持活动状态。
例如,如果您有大量的二进制图像对象,您可能希望将每个对象的名称关联起来。如果您使用Python字典将名称映射到图像或将图像映射到名称,则图像对象将保持活动状态,只是因为它们在字典中显示为值或键。模块提供的WeakKeyDictionary
和WeakValueDictionary
类weakref
是一种替代方法,它使用弱引用来构造映射,这些映射不会仅仅因为它们出现在映射对象中而使对象保持活动状态。例如,如果一个图像对象是a中的一个值WeakValueDictionary
,那么当对该图像对象的最后剩余引用是弱映射所持有的弱引用时,垃圾收集可以回收该对象,并且简单地删除其在弱映射中的对应条目。
WeakKeyDictionary
并WeakValueDictionary
在其实现中使用弱引用,在弱引用上设置回调函数,在通过垃圾回收回收键或值时通知弱字典。大多数程序应该发现,使用这些弱字典类型之一是他们需要的 - 通常不需要直接创建自己的弱引用。弱字典实现所使用的底层机器由weakref
模块公开,以利于高级应用。
并非所有的对象都可以被弱引用。那些可以包含类实例,用Python编写的函数(但不包含在C中)的函数,方法(绑定和非绑定),集合,frozensets,文件对象,生成器,类型对象,DBcursor
来自bsddb
模块的对象,套接字,数组, ,正则表达式模式对象和代码对象。
在版本2.4中进行了更改:增加了对文件,套接字,数组和模式的支持。
在版本2.7中进行了更改:添加了对thread.lock,threading.Lock和代码对象的支持。
几种内置类型,例如list
和dict
不直接支持弱引用,但可以通过子类添加支持:
class Dict(dict):
pass
obj = Dict(red=1, green=2, blue=3) # this object is weak referenceable
CPython实现细节:
其他内置类型,例如tuple
和long
不支持弱引用,即使在子类化时也是如此。
扩展类型可以很容易地支持弱引用; 请参阅弱参考支持。
class weakref.ref(object[, callback])
返回对象
的弱引用。如果指示对象
仍然存在,则可以通过调用参考对象
来检索原始对象
; 如果所指对象
不再存在,则调用引用对象
将导致None
返回。如果提供了回调
而没有提供回调
None
,并且返回的weakref对象
仍然存在,则当对象
即将完成时将调用回调
; 弱引用对象
将作为回调
的唯一参数传递; 所指对象
将不再可用。
允许为同一个对象构造许多弱引用。为每个弱引用注册的回调将从最近注册的回调调用到最早的注册回调。
回调引发的异常将在标准错误输出中注明,但不能传播; 它们的处理方式与从对象__del__()
方法中引发的异常完全相同。
弱引用可哈希如果对象
是可哈希。即使删除对象
后,它们仍会保留其哈希值。如果hash()
仅在对象
被删除后第一次被调用,则调用将会引发TypeError
。
弱引用支持测试的平等,但不排序。如果参照物仍然存在,则两个参照物与它们的参照物具有相同的平等关系(不管回调
)。如果任何对象已被删除,则只有当引用对象是同一对象时,引用才相等。
在版本2.4中更改:现在这是一个子类型而不是工厂函数; 它来自于object
。
weakref.proxy(object[, callback])
将代理返回给使用弱引用的对象
。这支持在大多数情况下使用代理,而不需要使用弱引用对象
的显式解引用。返回的对象
将具有式的任一ProxyType
或CallableProxyType
,这取决于是否对象
是可调用。代理对象
不可指派,不管指示对象
如何; 这避免了一些与它们的根本可变性有关的问题,并防止它们用作字典键。回调
与该函数的同名参数相同ref()
。
weakref.getweakrefcount(object)
返回引用对象
的弱引用和代理的数量。
weakref.getweakrefs(object)
回到这指的是所有弱引用和代理对象
的列表对象
。
class weakref.WeakKeyDictionary([dict])
弱映射键的映射类。当不再有对键的强烈引用时,字典中的条目将被丢弃。这可用于将附加数据与应用程序其他部分拥有的对象关联,而无需向这些对象添加属性。这对覆盖属性访问的对象可能特别有用。
注释
警告:因为WeakKeyDictionary
是建立在Python字典的基础之上的,所以它在迭代时不能改变大小。这可能难以确保,WeakKeyDictionary
因为程序在迭代过程中执行的操作可能会导致字典中的项目“通过魔法”消失(作为垃圾收集的副作用)。
WeakKeyDictionary
对象具有以下附加方法。这些直接暴露内部引用。这些引用在使用时并不保证是“实时”的,因此调用引用的结果需要在使用之前进行检查。这可以用来避免创建引用,这会导致垃圾回收器将密钥保持在比需要更长的时间。
WeakKeyDictionary.iterkeyrefs()
将弱引用的迭代返回给键。
2.5版本中的新功能。
WeakKeyDictionary.keyrefs()
返回密钥的弱引用列表。
2.5版本中的新功能。
class weakref.WeakValueDictionary([dict])
弱映射值的映射类。当没有对该值的强引用时,字典中的条目将被丢弃。
注意
警告:因为a WeakValueDictionary
是建立在Python字典的基础之上的,所以它在迭代时不能改变大小。这可能难以确保,WeakValueDictionary
因为程序在迭代过程中执行的操作可能会导致字典中的项目“通过魔法”消失(作为垃圾收集的副作用)。
WeakValueDictionary
对象具有以下附加方法。这些方法有相同的问题,作为iterkeyrefs()
和keyrefs()
方法的WeakKeyDictionary
对象。
WeakValueDictionary.itervaluerefs()
将弱引用的迭代返回给值。
2.5版本中的新功能。
WeakValueDictionary.valuerefs()
返回值的弱引用列表。
2.5版本中的新功能。
class weakref.WeakSet([elements])
设置对其元素保持弱引用的类。当没有强引用时,元素将被丢弃。
2.7版本的新功能。
weakref.ReferenceType
弱引用对象的类型对象。
weakref.ProxyType
不可调用对象的代理类型对象。
weakref.CallableProxyType
可调用对象的代理的类型对象。
weakref.ProxyTypes
包含代理的所有类型对象的序列。这可以更简单地测试一个对象是否是代理而不依赖于命名这两种代理类型。
exception weakref.ReferenceError
使用代理对象但已收集基础对象时引发异常。这与标准ReferenceError
例外相同。
1. Weak Reference Objects
弱引用对象没有属性或方法,但是允许通过调用它来获得指示对象,如果它仍然存在的话:
>>> import weakref
>>> class Object:
... pass
...
>>> o = Object()
>>> r = weakref.ref(o)
>>> o2 = r()
>>> o is o2
True
如果所指对象不再存在,则调用引用对象返回None
:
>>> del o, o2
>>> print r()
None
测试弱参考对象是否仍然存在应该使用表达式来完成ref() is not None
。通常,需要使用引用对象的应用程序代码应该遵循以下模式:
# r is a weak reference object
o = r()
if o is None:
# referent has been garbage collected
print "Object has been deallocated; can't frobnicate."
else:
print "Object is still live!"
o.do_something_useful()
对“活力”使用单独的测试会在线程应用程序中创建竞争条件; 另一个线程可能会导致弱引用在调用弱引用之前变为无效状态; 上面显示的习语在线程应用程序以及单线程应用程序中是安全的。
专用版本的ref
对象可以通过子类创建。这用于实现WeakValueDictionary
该映射中的每个条目以减少内存开销。这对于将附加信息与引用关联起来可能最为有用,但也可以用于在调用中插入附加处理以检索指示对象。
这个例子展示了如何使用一个子类ref
来存储关于一个对象的附加信息并影响访问对象时返回的值:
import weakref
class ExtendedRef(weakref.ref):
def __init__(self, ob, callback=None, **annotations):
super(ExtendedRef, self).__init__(ob, callback)
self.__counter = 0
for k, v in annotations.iteritems():
setattr(self, k, v)
def __call__(self):
"""Return a pair containing the referent and the number of
times the reference has been called.
"""
ob = super(ExtendedRef, self).__call__()
if ob is not None:
self.__counter += 1
ob = (ob, self.__counter)
return ob
2.例子
这个简单的例子展示了应用程序如何使用对象ID来检索它以前见过的对象。然后,可以在其他数据结构中使用对象的ID,而不强制对象保持活动状态,但如果对象仍然可以通过ID检索对象,则仍然可以使用ID检索对象。
import weakref
_id2obj_dict = weakref.WeakValueDictionary()
def remember(obj):
oid = id(obj)
_id2obj_dict[oid] = obj
return oid
def id2obj(oid):
return _id2obj_dict[oid]