weakref模塊的作用
weakref模塊支持對象的弱引用。正常的引用會增加對象的引用數,並避免它被垃圾回收。但結果並不是如期望中那樣,比如有時可能會出現一個循環引用,
或者有時需要內存時可能要刪除對象的緩存。弱引用是一個不能避免對象被自動清理的對象句柄。
1、對象的弱引用

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: <__main__.ExpensiveObject object at 0x000001E72262EB88> ref: <weakref at 0x000001E722633598; to 'ExpensiveObject' at 0x000001E72262EB88> r(): <__main__.ExpensiveObject object at 0x000001E72262EB88> deleting obj (Deleting <__main__.ExpensiveObject object at 0x000001E72262EB88>) r(): None
2、對象引用回調

import weakref class ExpensiveObject: def __del__(self): print('(Deleting {})'.format(self)) def callback(reference): """刪除對象后,進行回調""" 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())
運行效果
obj: <__main__.ExpensiveObject object at 0x000002819406EE08> ref: <weakref at 0x0000028194073688; to 'ExpensiveObject' at 0x000002819406EE08> r(): <__main__.ExpensiveObject object at 0x000002819406EE08> deleting obj (Deleting <__main__.ExpensiveObject object at 0x000002819406EE08>) callback(<weakref at 0x0000028194073688; dead>) r(): None
3、清理的弱引用,最終回收處理

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
運行效果
(Deleting <__main__.ExpensiveObject object at 0x00000188B703EB88>) on_finalize(('extra argument',))
4、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]))
運行效果
python3 weakref_finalize_atexit.py 1 on_finalize(('extra argument',)) (Deleting <__main__.ExpensiveObject object at 0x00000295B11FED08>) python3 weakref_finalize_atexit.py 0
5、在finalize引用對象的時候,del對象,內存中的對象是不會被gc回收的

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('在GC中發現未收集的對象')
運行效果
在GC中發現未收集的對象
6、finalize提供callable是實例obj的一個綁定方法,所以最終化方法保留了obj的一個引用,它不能被刪除和被回收。

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('在GC中發現未收集的對象')
運行效果
在GC中發現未收集的對象
7、代理弱引用

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)
運行效果
via obj: My Object via ref: My Object via proxy: My Object (Deleting <__main__.ExpensiveObject object at 0x000001FF9D3FECC8>) Traceback (most recent call last): File "xxxx", line 21, in <module> print('via proxy:', p.name) ReferenceError: weakly-referenced object no longer exists #代理對象不存在的時候,報異常
8、弱引用緩存對象

from pprint import pprint import weakref import gc 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): # 保持對象,以便任何弱引用,不會立即移除 all_refs = {} # 使用工廠創建緩存 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 # 刪除對對象的所有引用,但緩存除外 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)
運行效果
CACHE TYPE: <class 'dict'> all_refs = {'one': ExpensiveObject(one), 'three': ExpensiveObject(three), 'two': ExpensiveObject(two)} Before, cache contains: ['one', 'two', 'three'] one = ExpensiveObject(one) two = ExpensiveObject(two) three = ExpensiveObject(three) Cleanup: After, cache contains: ['one', 'two', 'three'] one = ExpensiveObject(one) two = ExpensiveObject(two) three = ExpensiveObject(three) demo returning (Deleting ExpensiveObject(one)) (Deleting ExpensiveObject(two)) (Deleting ExpensiveObject(three)) CACHE TYPE: <class 'weakref.WeakValueDictionary'> all_refs = {'one': ExpensiveObject(one), 'three': ExpensiveObject(three), 'two': ExpensiveObject(two)} Before, cache contains: ['one', 'two', 'three'] one = ExpensiveObject(one) two = ExpensiveObject(two) three = ExpensiveObject(three) Cleanup: (Deleting ExpensiveObject(one)) (Deleting ExpensiveObject(two)) (Deleting ExpensiveObject(three)) After, cache contains: [] demo returning