【发布时间】:2020-05-30 06:39:27
【问题描述】:
到目前为止,我一直在 Python 开发中犯了一个严重的错误:我一直假设流在其对应的对象超出范围时就会关闭。具体来说,我假设当一个文件或继承io.IOBase 的类的某个实例调用__del__ 时,它将运行对象的close 方法。但是,在执行以下代码后,我注意到情况肯定不是这样。
def wrap_close(old_close):
def new_close(*args, **kwargs):
print("closing")
return old_close(*args, **kwargs)
return new_close
f = open("tmp.txt")
f.close = wrap_close(f.close)
f.close() # prints "closing"
f = open("tmp.txt")
f.close = wrap_close(f.close)
del(f) # nothing printed
我的问题是,在调用 __del__ 方法时不自动关闭文件或流有什么好处?看起来实现起来很简单,但我想必须有理由允许流在其相应对象超出范围后保持打开状态。
【问题讨论】:
-
问题是关闭文件描述符是操作系统级别的任务,只有在调用
.close()时才能正确完成。del没有内置任何特殊行为来处理流 - 它只是从命名空间中删除对象,然后垃圾收集器将其堆肥。他们都不关心某处是否有打开的文件描述符,因为他们怎么知道? -
打印实际的文件描述符(通过
f.fileno())表明它们被重复使用,即文件已关闭。请注意,.close是 Python 级别的函数,而_io是用 C 实现的,其类将直接调用其 C 函数,而不是 Python 包装器。 -
James:如果您仔细阅读文档,您会发现无法保证已删除的对象会被垃圾回收。
-
@JamesMchugh 您是否将
__del__与del混淆了? Python 确实使用了_io.TextIOWrapper.__del__的等价物,但它是一个 C 函数,不调用 Python 级别的f.close。 -
@JamesMchugh
del仅取消链接名称。因此,这可能会将引用计数降低到 0(在 CPython 中)或最终触发垃圾收集(任何实现)。它不直接调用__del__。