2.8.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的所有位置或命名参数。
运行结果:
(Deleting <main.ExpensiveObject object at 0x0000000002F296D8>)
on_finalize((‘extra argument’,))
这个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对垃圾回收器可见。
运行结果:
found uncollected object in gc
使用所跟踪对象的一个绑定方法作为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的一个引用,它不能被删除和被垃圾回收。
运行结果:
found uncollected object in gc