我有一个打开文件进行写作的课程。在我的析构函数中,我调用关闭文件的函数:
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.
如果我在myobj.close()
之前致电del myobj
,我就不会遇到这个问题。那么为什么__del__()
没有被召唤?
答案 0 :(得分:8)
这不是del
所做的。遗憾的是__del__
与del
具有相同的名称,因为它们彼此无关。在现代术语中,__del__
方法将被称为终结器,而不是析构函数,差异很重要。
简单的区别在于,在调用析构函数时很容易保证,但是很少有人保证何时调用__del__
并且永远不会被调用。有许多不同的情况可以导致这种情况。
如果您想要词法作用域,请使用with
语句。否则,请直接致电myobj.close()
。 del
语句只删除引用,而不删除对象。
我找到了另一个答案(link)来回答更详细的问题。遗憾的是,对该问题的接受答案包含了令人震惊的错误。
修改:评论员指出,您需要继承object
。这很好,但仍然可能永远不会调用__del__
(你可能会变得幸运)。请参阅上面的链接答案。
答案 1 :(得分:8)
您确定要使用__del__
吗?有issues __del__
和垃圾收集。
您可以将MyClass改为context manager:
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离开myobj.__exit__
时,将调用和self.__fileHandle__.close()
(以及with-block
)。
答案 2 :(得分:2)
您的代码应该继承自object
- 不这样做已被视为已过期(特殊情况除外)至少六年。
您可以在此处阅读__del__
:http://docs.python.org/reference/datamodel.html#object.del
您需要从object
继承的简短版本是__del__
在新式课程中只是“神奇”。
如果您需要依赖于调用终结器,我强烈建议您使用其他答案中建议的上下文管理器方法,因为这是一种可移植的强大解决方案。
答案 3 :(得分:0)
也许其他东西正在引用它,这就是为什么__del__
没有被调用的原因。
考虑以下代码:
#!/usr/bin/env python
import time
class NiceClass():
def __init__(self, num):
print "Make %i" % num
self.num = num
def __del__(self):
print "Unmake %i" % self.num
x = NiceClass(1)
y = NiceClass(2)
z = NiceClass(3)
lst = [x, y, z]
time.sleep(1)
del x
del y
del z
time.sleep(1)
print "Deleting the list."
del lst
time.sleep(1)
在我们删除引用它们的列表之前,它不会调用__del__
个NiceClass
个实例。
与C ++不同,__del__
没有被无条件地调用以按需销毁对象。 GC使事情变得更加艰难。以下是一些信息:http://arctrix.com/nas/python/gc/