首先,del 语句不一定调用 del() —— 它只是减少对象的引用计数,如果(引用计数)达到零,才会调用 del()。
如果数据结构包含循环链接(比如树的每个子节点都带有父节点的引用,而每个父节点也带有子节点的列表),则引用计数永远不会回零。尽管 Python 偶尔会用某种算法检测这种循环引用,但在数据结构的最后一条引用消失之后,垃圾收集器可能还要过段时间才会运行,因此 del() 方法可能会在不方便和随机的时刻被调用。这对于重现一个问题,是非常不方便的。更糟糕的是,各个对象的 del() 方法是以随机顺序执行的。虽然可以运行 gc.collect() 来强制执行垃圾回收工作,但仍会存在一些对象永远不会被回收的失控情况。
尽管有垃圾回收器的存在,但为对象定义显式的 close() 方法,只要一用完即可供调用,这依然是一个好主意。这样 close() 方法即可删除引用子对象的属性。请勿直接调用 del() —— 而 del() 应该调用 close(),并且应能确保可以对同一对象多次调用 close() 。
另外一种可能的原因呢,就是避免循环引用的做法是利用 weakref 模块,该模块允许指向对象但不增加其引用计数。例如,树状数据结构应该对父节点和同级节点使用弱引用(如果真要用的话!)
最后提一下,如果 del() 方法引发了异常,会将警告消息打印到 sys.stderr 。