Python数据结构与算法(11)---对象的非永久引用weakref

简介: Python数据结构与算法(11)---对象的非永久引用weakref

对象的非永久引用weakref


weakref库支持对象的弱引用。正常的引用会增加对象的引用数,并避免它被垃圾回收。但结果并不总是期望的那样。


比如,有时候可能会出现一个循环引用,或者有时候需要内存时,可能要删除对象的缓存。而弱引用是一个不能避免对象被自动清理的对象句柄。


引用

下面,我们来看一个简单的例子,示例如下:

import weakref
class MyObject:
    def __del__(self):
        print('删除{}'.format(self))
obj = MyObject()
r = weakref.ref(obj)
print('obj:', obj)
print('ref:', r)
print('r():', r())
print("删除对象引用")
del obj
print('r():', r())


运行之后,控制台输出如下:


这里对象的弱引用需要通过ref类来管理,要获取原对象,可以调用引用对象。这里,由于obj在第二次调用引用之前已经被删除,所以ref返回None。


引用回调

ref的构造函数还有一个可选参数,删除所所应用的对象时,会调用这个函数,也就是java里常说的回调函数。示例如下:

import weakref
class MyObject:
    def __del__(self):
        print('删除{}'.format(self))
def callBack(reference):
    print('callback{}'.format(reference))
obj = MyObject()
r = weakref.ref(obj, callBack)
print('obj:', obj)
print('ref:', r)
print('r():', r())
print("删除对象引用")
del obj
print('r():', r())


相对于前面的代码,除了多出一个方法,以及一个参数之外,其他的代码一模一样。运行之后,效果如下:


当引用已经死亡,不再引用原对象时,就会触发这个回调函数。因为回调函数接收的参数是引用对象,所以这个特性的一种用法是从缓存中删除弱引用对象。


最终化对象

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


示例如下:

import weakref
class MyObject:
    def __del__(self):
        print('删除{}'.format(self))
def on_finalize(*args):
    print('on_finalize-----{}'.format(args))
obj=MyObject()
weakref.finalize(obj,on_finalize,'额外参数')
del obj


运行之后,效果如下:


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


不过,finalize还有一个属性atexit,它用来控制程序退出时是否调用这个回调(如果还没有调用的话),示例如下:

f = weakref.finalize(obj, on_finalize, '额外参数')
f.atexit = False


这里,只需要改变最后两行代码,运行不会有任何结果。这是因为设置atexit为False表示不调用这个回调。


需要注意的是,因为finalize跟踪了一个对象的一个引用,那么便会导致这个对象引用被保留,所以这个对象永远不会被垃圾回收。


代理

有时候使用代理比使用弱引用更方便。使用代理可以像使用原对象一样,而且不要求再访问对象之前先调用代理。


这说明,可以将代理传递到一个库,而这个库并不知道它接收的是一个引用而不是真正的对象。


示例如下:

import weakref
class MyObject:
    def __init__(self, name):
        self.name = name
    def __del__(self):
        print('删除{}'.format(self))
obj = MyObject("MyObject")
r = weakref.ref(obj)
p = weakref.proxy(obj)
print('obj:', obj.name)
print('ref:', r().name)
print('proxy:', p.name)
del obj
print('proxy:', p.name)


运行之后,效果如下:

可以看到,如果引用对象已经被删除,那么再访问代理会产生一个ReferenceError异常。


缓存对象

ref和proxy类被认为是底层的。尽管它们对于维护单个对象的弱引用很有用,并且还支持对循环引用的垃圾回收。


但WeakKeyDictionary和WeakValueDictionary类为创建多个对象的缓存提供了一个更合适的API。


WeakValueDictionary类使用它包含的值的弱引用,当其他代码不再真正使用这些值时,则允许垃圾回收。


利用垃圾回收器的显式调用,下面展示了使用常规字典和WeakValueDictionary完成内存处理的区别。

import weakref
import gc
from pprint import pprint
gc.set_debug(gc.DEBUG_UNCOLLECTABLE)
class MyObject:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'MyObject---{}'.format(self.name)
    def __del__(self):
        print('删除---{}'.format(self))
def demo(cache_factory):
    all_refs = {}
    print('缓存类型:', cache_factory)
    cache = cache_factory()
    for name in ['one', 'two', 'three']:
        o = MyObject(name)
        cache[name] = o
        all_refs[name] = o
        del o
    print(" all_refs=", end='')
    pprint(all_refs)
    print("开始 缓存包括:", list(cache.keys()))
    for name, value in cache.items():
        print('{}={}'.format(name, value))
        del value
    print('清理')
    del all_refs
    gc.collect()
    print('结束 缓存包括:', list(cache.keys()))
    for name, value in cache.items():
        print('{}={}'.format(name, value))
    print("返回")
    return
demo(dict)
print()
demo(weakref.WeakValueDictionary)


运行之后,效果如下:


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

相关文章
|
21天前
|
机器学习/深度学习 算法 搜索推荐
Machine Learning机器学习之决策树算法 Decision Tree(附Python代码)
Machine Learning机器学习之决策树算法 Decision Tree(附Python代码)
|
1月前
|
机器学习/深度学习 算法 数据挖掘
请解释Python中的决策树算法以及如何使用Sklearn库实现它。
决策树是监督学习算法,常用于分类和回归问题。Python的Sklearn库提供了决策树实现。以下是一步步创建决策树模型的简要步骤:导入所需库,加载数据集(如鸢尾花数据集),划分数据集为训练集和测试集,创建`DecisionTreeClassifier`,训练模型,预测测试集结果,最后通过`accuracy_score`评估模型性能。示例代码展示了这一过程。
|
1天前
|
机器学习/深度学习 算法 搜索推荐
Python用机器学习算法进行因果推断与增量、增益模型Uplift Modeling智能营销模型
Python用机器学习算法进行因果推断与增量、增益模型Uplift Modeling智能营销模型
27 12
|
6天前
|
算法 数据可视化 Python
Python贝叶斯推断Metropolis-Hastings(M-H)MCMC采样算法的实现
Python贝叶斯推断Metropolis-Hastings(M-H)MCMC采样算法的实现
11 0
|
6天前
|
数据可视化 算法 数据挖掘
PYTHON实现谱聚类算法和改变聚类簇数结果可视化比较
PYTHON实现谱聚类算法和改变聚类簇数结果可视化比较
|
7天前
|
算法 数据可视化 Python
Python中LARS和Lasso回归之最小角算法Lars分析波士顿住房数据实例
Python中LARS和Lasso回归之最小角算法Lars分析波士顿住房数据实例
13 0
|
7天前
|
机器学习/深度学习 算法 Python
使用Python实现集成学习算法:Bagging与Boosting
使用Python实现集成学习算法:Bagging与Boosting
18 0
|
8天前
|
Python
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
50 0
|
8天前
|
Python
python学习-函数模块,数据结构,字符串和列表(下)
python学习-函数模块,数据结构,字符串和列表
49 0
|
8天前
|
缓存 算法 Python
python算法对音频信号处理Sonification :Gauss-Seidel迭代算法
python算法对音频信号处理Sonification :Gauss-Seidel迭代算法

热门文章

最新文章