这个方法的作用是将一个对象从内存中清除之前,可以有机会做一些清理工作。
这里之所以用 “有机会” 来形容是因为这个方法是不稳定的:它并不总是在del语句删除对象时被调用,当一个对象的命名空间被删除时,它也不一定被调用。
所以同样的需求最好使用上下文管理器来实现。
python(Cpython)中对象会包含一个引用计数。__del__方法只有当引用技术为0时才会执行。
class f:
def __del__(self):
print(id(self))
>> a = [f(),f()]
>> b = a
>> del a # 还有b在引用,所以没有执行__del__
>> del b
2414194009984
2414194010824
当存在循环引用时,执行del函数,对应的__del__方法将不会执行。
class Parent:
def __init__(self, *children):
self.children = children
for child in self.children:
child.parent = self
def __del__(self):
print('Remove {} id {}'.format(self.__class__, id(self)))
class Child:
def __del__(self):
print('Remove {} id {}'.format(self.__class__,id(self)))
>> p = Parent(Child(),Child())
>> del p
# 并没有执行__del__方法的输出
这时可以使用垃圾回收接口–GC,来回收和显示这些不能删除的对象。
>> import gc
>> gc.collect()
Remove <class '__main__.Child'> id 2408580851920
Remove <class '__main__.Child'> id 2408580852144
Remove <class '__main__.Parent'> id 2408580852872
默认对象间的引用为强引用,或者叫直接引用。上面的循环引用就是使用的强引用。这会影响引用计数。
如果我们需要循环引用,又想把清理代码写在__del__中,可以使用弱引用。
弱引用和强引用的寻找过程也是不同的:
# 弱引用
x.parent() #在函数中存在寻找父对象的逻辑
# 强引用
x.parent #直接指向的就是父对象
weakref模块定义了一系列使用弱引用而没有使用强引用的集合,它可以让我们创建一种特殊的字典,当这种字典的对象没有用时,可以保证被垃圾回收。
上面的类可以更改为这样的:
import weakref
class Parent:
def __init__(self, *children):
self.children = children
for child in self.children:
child.parent = weakref.ref(self) #使用weakref创建弱引用
def __del__(self):
print('Remove {} id {}'.format(self.__class__, id(self)))
class Child:
# 这里添加了一个使用 parent属性的函数,来演示区别
def print_parent(self):
parent = self.parent()
if parent is not None:
print(parent)
else:
# 为None的情况就是parent对象被内存回收机制处理了
print('the parent instance was garbage collected')
def __del__(self):
print('Remove {} id {}'.format(self.__class__,id(self)))