1. weakref对象的非永久引用

weakref模块支持对象的弱引用。正常的引用会增加对象的引用数,并避免它被垃圾回收。但结果并不总是如期望中的那样,比如有时可能会出现一个循环引用,或者有时需要内存时可能要删除对象的缓存。弱引用(weak reference)是一个不能避免对象被自动清理的对象句柄。

1.1 引用

对象的弱引用要通过ref类来管理。要获取原对象,可以调用引用对象。

import weakref

class ExpensiveObject:

    def __del__(self):
print('(Deleting {})'.format(self)) obj = ExpensiveObject()
r = weakref.ref(obj) print('obj:', obj)
print('ref:', r)
print('r():', r()) print('deleting obj')
del obj
print('r():', r())

在这里,由于obj在第二次调用引用之前已经被删除,所以ref返回None。

1.2 引用回调

ref构造函数接受一个可选的回调函数,删除所引用的对象时会调用这个函数。

import weakref

class ExpensiveObject:

    def __del__(self):
print('(Deleting {})'.format(self)) def callback(reference):
"""Invoked when referenced object is deleted"""
print('callback({!r})'.format(reference)) obj = ExpensiveObject()
r = weakref.ref(obj, callback) print('obj:', obj)
print('ref:', r)
print('r():', r()) print('deleting obj')
del obj
print('r():', r())

当引用已经“死亡”而且不再引用原对象时,这个回调会接受这个引用对象作为参数。这个特性的一种用法就是从缓存中删除弱引用对象。

1.3 最终化对象

清理弱引用时要对资源完成更健壮的管理,可以使用finalize将回调与对象关联。finalize实例会一直保留(直到所关联的对象被删除) ,即使应用并没有保留最终化对象的引用。

import weakref

class ExpensiveObject:

    def __del__(self):
print('(Deleting {})'.format(self)) def on_finalize(*args):
print('on_finalize({!r})'.format(args)) obj = ExpensiveObject()
weakref.finalize(obj, on_finalize, 'extra argument') del obj

finalize的参数包括要跟踪的对象,对象被垃圾回收时要调用的callable,以及传入这个callable的所有位置或命名参数。

这个finalize实例有一个可写属性atexit,用来控制程序退出时是否调用这个回调(如果还未调用)。

import sys
import weakref class ExpensiveObject: def __del__(self):
print('(Deleting {})'.format(self)) def on_finalize(*args):
print('on_finalize({!r})'.format(args)) obj = ExpensiveObject()
f = weakref.finalize(obj, on_finalize, 'extra argument')
f.atexit = bool(int(sys.argv[1]))

默认设置是调用这个回调。将atexit设置为false会禁用这种行为。

如果向finalize实例提供所跟踪对象的一个引用,这便会导致一个引用被保留,所以这个对象永远不会被垃圾回收。

import gc
import weakref class ExpensiveObject: def __del__(self):
print('(Deleting {})'.format(self)) def on_finalize(*args):
print('on_finalize({!r})'.format(args)) obj = ExpensiveObject()
obj_id = id(obj) f = weakref.finalize(obj, on_finalize, obj)
f.atexit = False del obj for o in gc.get_objects():
if id(o) == obj_id:
print('found uncollected object in gc')

如上所示,尽管obj的显式引用已经删除,但是这个对象仍保留,通过f对垃圾回收器可见。

使用所跟踪对象的一个绑定方法作为callable也可以适当地避免对象最终化。

import gc
import weakref class ExpensiveObject: def __del__(self):
print('(Deleting {})'.format(self)) def do_finalize(self):
print('do_finalize') obj = ExpensiveObject()
obj_id = id(obj) f = weakref.finalize(obj, obj.do_finalize)
f.atexit = False del obj for o in gc.get_objects():
if id(o) == obj_id:
print('found uncollected object in gc')

由于为finalize提供的callable是实例obj的一个绑定方法,所以最终化方法保留了obj的一个引用,它不能被删除和被垃圾回收。

1.4 代理

有时使用代理比较弱引用更方便。使用代理可以像使用原对象一样,而且不要求在访问对象之前先调用代理。这说明,可以将代理传递到一个库,而这个库并不知道它接收的是一个引用而不是真正的对象。

import weakref

class ExpensiveObject:

    def __init__(self, name):
self.name = name def __del__(self):
print('(Deleting {})'.format(self)) obj = ExpensiveObject('My Object')
r = weakref.ref(obj)
p = weakref.proxy(obj) print('via obj:', obj.name)
print('via ref:', r().name)
print('via proxy:', p.name)
del obj
print('via proxy:', p.name)

如果引用对象被删除后再访问代理,会产生一个ReferenceError异常。

1.5 缓存对象

ref和proxy类被认为是“底层”的。尽管它们对于维护单个对象的弱引用很有用,并且还支持对循环引用的垃圾回收,但WeakKeyDictionary和WeakValueDictionary类为创建多个对象的缓存提供了一个更适合的API。

WeakValueDictionary类使用它包含的值的弱引用,当其他代码不再真正使用这些值时,则允许垃圾回收。利用垃圾回收器的显式调用,下面展示了使用常规字典和WeakValueDictionary完成内存处理的区别。

import gc
from pprint import pprint
import weakref gc.set_debug(gc.DEBUG_UNCOLLECTABLE) class ExpensiveObject: def __init__(self, name):
self.name = name def __repr__(self):
return 'ExpensiveObject({})'.format(self.name) def __del__(self):
print(' (Deleting {})'.format(self)) def demo(cache_factory):
# hold objects so any weak references
# are not removed immediately
all_refs = {}
# create the cache using the factory
print('CACHE TYPE:', cache_factory)
cache = cache_factory()
for name in ['one', 'two', 'three']:
o = ExpensiveObject(name)
cache[name] = o
all_refs[name] = o
del o # decref print(' all_refs =', end=' ')
pprint(all_refs)
print('\n Before, cache contains:', list(cache.keys()))
for name, value in cache.items():
print(' {} = {}'.format(name, value))
del value # decref # remove all references to the objects except the cache
print('\n Cleanup:')
del all_refs
gc.collect() print('\n After, cache contains:', list(cache.keys()))
for name, value in cache.items():
print(' {} = {}'.format(name, value))
print(' demo returning')
return demo(dict)
print() demo(weakref.WeakValueDictionary)

如果循环变量指示所缓存的值,那么这些循环变量必须被显式清除,以使对象的引用数减少。否则,垃圾回收器不会删除这些对象,它们仍然会保留在缓存中。类似地,all_refs变量用来保存引用,以防止它们被过早地垃圾回收。

WeakKeyDictionary的工作与之类似,不过使用了字典中键的弱引用而不是值的弱引用。

Python3标准库:weakref对象的非永久引用的更多相关文章

  1. Python3标准库使用样例

    原:https://doughellmann.com/blog/the-python-3-standard-library-by-example/the-python-3-standard-libra ...

  2. 7.Python3标准库--文件系统

    ''' Python的标准库中包含大量工具,可以处理文件系统中的文件,构造和解析文件名,还可以检查文件内容. 处理文件的第一步是要确定处理的文件的名字.Python将文件名表示为简单的字符串,另外还提 ...

  3. Python3 标准库

    Python3标准库 更详尽:http://blog.csdn.net/jurbo/article/details/52334345 文本 string:通用字符串操作 re:正则表达式操作 diff ...

  4. 8.Python3标准库--数据持久存储与交换

    ''' 持久存储数据以便长期使用包括两个方面:在对象的内存中表示和存储格式之间来回转换数据,以及处理转换后数据的存储区. 标准库包含很多模块可以处理不同情况下的这两个方面 有两个模块可以将对象转换为一 ...

  5. python023 Python3 标准库概览

    Python3 标准库概览 操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作 ...

  6. 比较两个文件的异同Python3 标准库difflib 实现

    比较两个文件的异同Python3 标准库difflib 实现 对于要比较两个文件特别是配置文件的差异,这种需求很常见,如果用眼睛看,真是眼睛疼. 可以使用linux命令行工具diff a_file b ...

  7. python3标准库总结

    Python3标准库 操作系统接口 os模块提供了不少与操作系统相关联的函数. ? 1 2 3 4 5 6 >>> import os >>> os.getcwd( ...

  8. 1.Python3标准库--前戏

    Python有一个很大的优势便是在于其拥有丰富的第三方库,可以解决很多很多问题.其实Python的标准库也是非常丰富的,今后我将介绍一下Python的标准库. 这个教程使用的书籍就叫做<Pyth ...

  9. 记阮一峰---JavaScript 标准参考教程之标准库-Object对象

    在看到阮大神的-标准库-Object对象时 有个 类型判断类型 方法可能以后会用到.特此记录一下 4.3:toString()的应用:判断数据类型 Object.prototype.toString方 ...

随机推荐

  1. SSM前后端分离/不分离对比Demo

    之前某些原因,整理了一个小的Demo,用于演示.个人认为在SSM前后端不分离的基础上在前端处理上比较麻烦一点之后就是注解的使用.总结一些对比,仅是自己掌握的,不够严谨,不足之处请大佬批评指正. 路由控 ...

  2. mysql数据库的备份与数据恢复

    一.定时备份数据库  前段时间工作中搭建了HttpRunnerManager的接口自动化测试平台,由于平台中没有提供用例下载的功能及权限管理功能,自己也不会写前端,于是就想了办法,那就是备份数据库,如 ...

  3. Jmeter使用—使用 HTTP代理服务器抓取接口

    这里说一下怎么使用jmeter的HTTP代理服务器来抓取接口. 首先,打开jmeter,进入主页面,然后在对工作台(Jmeter版本4.0)点击右键->添加->非测试元件->HTTP ...

  4. NVIDIA DRIVE

      NVIDIA 驱动安装(超详细) ref1: https://blog.csdn.net/qlulibin/article/details/78714596 ref2:https://www.cn ...

  5. http轮询,长轮询

    轮询,长轮询 轮询 轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 优点:后端程序编写比较容易. 缺点:请求中有大半是无用,浪费带宽和服务器资源. 实例:适于小 ...

  6. X-CTF(REVERSE入门) re1

    运行程序 32位ida打开,shift+f12查看运行时的中文,这里双击flag get字符串进入rdata段 双击后面的函数,进入text段,小的窗口视图里可以看见汇编代码调用函数的句子 右边的即是 ...

  7. Git详解之服务部署

    前言 到目前为止,你应该已经学会了使用 Git 来完成日常工作.然而,如果想与他人合作,还需要一个远程的 Git 仓库.尽管技术上可以从个人的仓库里推送和拉取修改内容,但我们不鼓励这样做,因为一不留心 ...

  8. 冬日曙光——回溯CNN的诞生

    前言 卷积神经网络(CNN)作为深度学习的重要一支,在当前计算机视觉领域应用相当广泛.本文回顾了深度学习的发展历程,讲述CNN基本的理论概念和第一代卷积神经网络LeNet-5的建立.文章言有不当之处, ...

  9. axure如何实现提示框3s后自动消失

    本示例基于axure8 实现 1.先做两个元件,一个按钮,一个提示框 2.将弹框“发布成功提示”设置为,页面载入时隐藏,这样预览页面时,该弹框是隐藏状态 3.给按钮添加交互样式,如下: 4.预览,点击 ...

  10. VC简单操作mysql

    #include <iostream> #include <winsock.h> #include <mysql.h> #pragma comment(lib, & ...