del MyClass 不会调用 object.__del__()

6 投票
4 回答
6485 浏览
提问于 2025-04-17 10:30

我有一个类,用来打开文件进行写入。在我的析构函数里,我调用了一个关闭文件的函数:

class MyClass:
    def __del__(self):
        self.close()

    def close(self):
        if self.__fileHandle__ is not None:
                self.__fileHandle__.close()

但是当我用这样的代码删除这个对象时:

myobj = MyClass()
myobj.open()
del myobj

如果我尝试重新创建这个对象,就会出现一个值错误:

ValueError: The file 'filename' is already opened.  Please close it before reopening in write mode.

而如果我在 del myobj 之前调用 myobj.close(),就不会出现这个问题。那么,为什么 __del__() 没有被调用呢?

4 个回答

2

你的代码应该继承自 object,不这样做在过去六年里被认为是过时的做法(当然有些特殊情况除外)。

你可以在这里了解 __del__ 的相关信息: http://docs.python.org/reference/datamodel.html#object.del

简单来说,为什么你需要继承自 object 是因为 __del__ 只有在新式类中才算是“魔法”。

如果你需要依赖于某个清理函数的调用,我强烈建议你使用其他答案中提到的上下文管理器的方法,因为那是一种可移植且可靠的解决方案。

8

其实,del__del__是两回事。很遗憾的是,它们的名字一样,但实际上没有任何关系。在现代的说法中,__del__这个方法应该叫做终结器,而不是析构器,这两者之间的区别很重要。

简单来说,析构器什么时候被调用是比较容易保证的,但对于__del__什么时候会被调用,你几乎没有什么保证,甚至可能永远不会被调用。这种情况可能有很多不同的原因。

如果你想要词法作用域,可以使用with语句。否则,直接调用myobj.close()就可以了。del语句只是删除引用,并不会删除对象。

我找到另一个答案(链接),它详细回答了不同的问题。很遗憾的是,那道题的被接受答案里有一些严重的错误。

编辑:正如评论者所提到的,你需要从object继承。这是可以的,但仍然有可能__del__永远不会被调用(你可能只是运气好)。请查看上面的链接答案。

8

你确定要使用 __del__ 吗?因为 __del__ 和垃圾回收有一些 问题

你可以把 MyClass 改成一个 上下文管理器,这样做:

class MyClass(object):
    def __enter__(self):
        return self
    def __exit__(self,ext_type,exc_value,traceback):
        if self.__fileHandle__ is not None:
                self.__fileHandle__.close()

这样一来,你就可以像这样使用 MyClass

with MyClass() as myobj:
    ...

当 Python 离开 with-block 时,myobj.__exit__(也就是 self.__fileHandle__.close())会被调用。

撰写回答