Python __del__ 处理时基类在子类之前被删除
背景
我知道如果我问关于Python析构函数的问题,大家通常会建议我使用上下文管理器。让我先解释一下我为什么不这样做。
我正在写一个logging.Handler
的子类。当一个实例被关闭时,它会向一个Queue.Queue发送一个信号值。如果没有这样做,第二个线程就会一直运行,等待Queue.Queue.get()完成。
我写这个是为了其他开发者考虑,所以我不想因为没有调用handler对象的close()而导致程序卡住。
因此,我在__del__()方法中添加了一个检查,以确保对象被正确关闭。
我知道循环引用可能会导致某些情况下失败,但对此我无能为力。
问题
这里有一些简单的示例代码:
explicit_delete = True
class Base:
def __del__(self):
print "Base class cleaning up."
class Sub(Base):
def __del__(self):
print "Sub-class cleaning up."
Base.__del__(self)
x = Sub()
if explicit_delete:
del x
print "End of thread"
当我运行这个代码时,得到的结果是我预期的:
Sub-class cleaning up.
Base class cleaning up.
End of thread
如果我在第一行把explicit_delete
设置为False
,我得到的结果是:
End of thread
Sub-class cleaning up.
Exception AttributeError: "'NoneType' object has no attribute '__del__'" in <bound method Sub.__del__ of <__main__.Sub instance at 0x00F0B698>> ignored
看起来在调用x.__del__()
之前,Base的定义就被移除了。
Python文档中关于__del__()的部分警告说,子类需要调用基类的方法以确保干净地删除,但在这里这似乎是不可能的。
你能看出我哪里出错了吗?
2 个回答
1
这里有一个可行的解决办法,不过可能不是最好的:
explicit_delete = False
class Base(object):
def __del__(self):
print "Base class cleaning up."
class Sub(Base):
base = Base
def __init__(self):
print 'stating'
def __del__(self):
print "Sub-class cleaning up."
self.base.__del__(self)
x = Sub()
if explicit_delete:
del x
print "End of thread"
你可以保留一个对基类的第二个引用。
2
你的代码有点误导,我试了一下,果然像你说的那样失败了。不过我写了类似这样的代码:
import threading
class Base( object ):
def __del__(self):
print "Base class cleaning up."
class Sub(Base):
def __del__(self):
print "Sub-class cleaning up."
Base.__del__( self )
def f():
x = Sub()
print "End of thread"
t = threading.Thread( target = f )
t.start()
t.join()
然后输出是:
End of thread
Sub-class cleaning up.
Base class cleaning up.
End of main thread.
所以我想在解释器关闭的时候,你不能依赖 __del__
方法(我觉得类对象是在实例之前被回收的?),但在那之前它们的表现是正常的。
也许让主线程保持活着,直到其他线程都结束,并且不要在主线程中创建你的 Handler 子类实例,这样就足够了?