当前位置: 首页 > news >正文

Python Cookbook-6.10 保留对被绑定方法的引用且支持垃圾回收

任务

你想保存一些指向被绑定方法的引用,同时还需要让关联的对象可以被垃圾收集机制处理。

解决方案

弱引用(weakreference)(弱引用在一个对象处于生存期时指向该对象,但如果没有其他正常的引用指向该对象时,这个对象不会被保留)在一些高级编程方法中是一个重要的工具。Python 标准库的 weakref模块允许我们使用弱引用。

然而,weakref的功能无法被直接应用于被绑定方法,除非你采取了一些特殊的预防措施。为了让一个对象在有引用指向其被绑定方法的时候能被垃圾回收机制处理,需要做一些封装工作。将下列代码存为一个名为weakmethod.py 的文件,并放入你的Python的sys.path目录中:

import weakref,new
class ref(object):'''能够封装任何可调用体,特别是被绑定方法,而且被绑定方法仍然能被回收处理。与此同时,提供一个普通的弱引用的接口'''def __init__(self,fn):try:#试图获得对象、函数和类o,f,c = fn.im_self,fn.im_func,fn,im_classexcept AttributeError:#非被绑定方法self._obj = Noneself._func = fnself._clas = Noneelse:#绑定方法if o is None:self._obj = None#…实际上没绑定else: self._obj = weakref.ref(o)#…确实绑定了self._func = fself._clas = cdef __call__(self):if self.obj is None:return self._funcelif self._obj()is None:return Nonereturn new.instancemethod(self._func,self.obj(),self._clas)

讨论

一个正常的被绑定方法拥有一个指向此方法所属对象的强引用。这意味着除非这个被绑定方法被消灭掉,否则该对象不能被当做垃圾重新回收。

>>> class C(object):def f(self):print "Hello"def __del__(self):print "C dying"
>>> c = C()
>>> cf = c.f
>>> del c#c眨巴眨巴眼睛活得好好的…
>>> del cf#…直到我们干掉了被绑定的方法,它才终于安心地去了
C dying

很多时候这种行为方式很方便,但有时它却达不到你想要的效果。比如,你想实现一个事件分发的系统,你可能不希望由于一个事件处理者(比如一个被绑定函数)的存在,整个关联对象都无法被回收。因而一个很自然的想法是使用弱引用。不过,一个普通的指向被绑定方法的 weakref.ref并不会按照我们的期望工作,那是因为被绑定方法是一级对象(frst-class objects)。指向被绑定方法的弱引用的保质期总是很短的,在解除引用时它们总是返回None,除非还有另外一个强引用指向了这个被绑定方法。

举个例子,下面的代码基于 Python 标准库 weakref模块,并不会打印“hello”,却会抛出一个异常:

>>> import weakref
>>> c = C()
>>> cf = weakref.ref(c.f)
>>> cf#先瞧瞧这是什么东西…
<weakref at 80ce394; dead>
>>> cf()()
Traceback(most recent call last):
File"", line 1, in ?
TypeError: object of type 'None' is not callable

另一方面,下面展示的在 weakmethod模块中的ref类则允许你使用指向被绑定方法的弱引用:

>>> import weakmethod
>>> cf = weakmethod.ref(c.f)
>>> cf()()# 哇哦!它是活的!
Hello
>>> del c#…然后就死掉了
C dying
>>> print cf()
None

调用 weakmethod.ref实例,即指向一个被绑定方法的引用,与调用 weakref.ref 指向一个函数对象的实例具有相同的语义:如果引用无效,它返回None;否则就返回引用。事实上,此例中它返回了一个新建的new.instancemethod(它持有一个指向对象的强引用,因此,应当确保不持有这个引用,除非你想让那个对象多存活一段时间)。

注意,本节的解决方案代码的设计很讲究,可以很容易地把任何你想封装的可调用体封入一个 ref实例中,无论是方法(绑定或未绑定的)、函数或其他任何东西。但只有当你试图封装一个被绑定的方法时,它才会有弱引用的语义,对其他的情况,ref就像一个普通(强)引用,一直指向处于生存期的可调用体。这种方式让可以用ref封装任意的可调用体,而无须为任何特殊情况做特殊处理。

如果需要的语义接近于 weakrefproxy 的语义,那就更容易实现了,例如从本节的 ref类派生一个子类。当你调用 proxy时,proxy会用相同的参数调用引用。如果被引用的对象已经消亡,会生成weakref.ReferenceError异常。下面是 proxy 类的一个实现:

class proxy(ref):def __call__(self,*args,**kwargs):func = ref.__call__(self)if func is None:raise weakref,ReferenceError('referent object is dead')else:return func(*args,**kwargs)def __eq__(self,other):if type(other) != type(self):return Falsereturn ref.__call__(self) == ref.__call__(other)

相关文章:

  • Eigen稀疏矩阵类 (SparseMatrix)
  • Centos7系统防火墙使用教程
  • 某东h5st_5.1(补环境)
  • qt/c++云对象浏览器
  • 文章记单词 | 第46篇(六级)
  • java函数式接口与方法引用
  • 八猴渲染器三维场景实时预览软件 Marmoset Toolbag 5.01 安装包免费下载
  • 山东大学离散数学第九章习题解析
  • C++ 为什么建议类模板定义在头文件中,而不定义在源文件中
  • Nacos详解
  • Python 第 12、13 节课 - 元组和列表
  • Linux基本指令(保姆级教学)
  • 【新技术】Testfy.js v3.0 深度解析与使用指南
  • 关于循环缓冲区
  • MUC基本知识
  • 基于javaweb的SpringBoot小说阅读系统设计与实现(源码+文档+部署讲解)
  • Threejs中顶视图截图
  • Python dotenv 使用指南:轻松管理项目环境变量
  • Bento4的安装和简单转码
  • Linux基础指令【上】
  • 核电开闸!国常会核准10台新机组,拉动超2000亿投资,新项目花落谁家?
  • 乌方称泽连斯基与特朗普进行简短会谈
  • 江苏、安徽跨省联动共治“样板间”:进一扇门可办两省事
  • 时代邻里:拟收购成都合达联行科技剩余20%股权
  • 航天科技集团质量技术部部长严泽想升任集团副总经理
  • 滁州一交通事故责任认定引质疑:民警和司法鉴定人被处罚,已中止诉讼