【问题标题】:Does Python GC close files too?Python GC 也会关闭文件吗?
【发布时间】:2018-09-05 20:50:57
【问题描述】:

考虑以下 Python (2.x) 代码:

for line in open('foo').readlines():
    print line.rstrip()

我假设由于打开的文件仍然未被引用,它必须自动关闭。我已经阅读了 Python 中的垃圾收集器,它释放了未使用对象分配的内存。 GC 是否也足以处理文件?

【问题讨论】:

标签: python file garbage-collection


【解决方案1】:

更新

对于当前版本的 python,明确的建议是明确关闭文件或使用with 语句。没有任何迹象表明 GC 将为您关闭文件。所以现在的答案应该是:也许,但不能保证。始终使用close()with 语句。

Python 3.8 docs 中的文字已更新为:

如果您没有使用with 关键字,那么您应该调用 f.close() 来关闭文件并立即释放它使用的所有系统资源。

警告:调用f.write()而不使用with关键字或调用f.close()可能会导致f.write()的参数没有完全写入磁盘,即使程序成功退出。

旧答案

取自Python 3.6 docs

如果您没有使用with 关键字,那么您应该调用f.close() 来关闭文件并立即释放它使用的所有系统资源。如果您没有明确关闭文件,Python 的垃圾收集器最终会销毁该对象并为您关闭打开的文件,但该文件可能会保持打开一段时间。另一个风险是不同的 Python 实现会在不同的时间进行这种清理。

是的,文件将自动关闭,但为了控制进程,您应该自己执行此操作或使用with 声明:

with open('foo') as foo_file:
    for line in foo_file.readlines():
        print line.rstrip()

foo_file 将在 with 块结束后关闭

Python 2.7 docs 中的措辞不同:

当你处理完一个文件后,调用 f.close() 来关闭它并释放它 打开的文件占用的任何系统资源。打电话后 f.close(),尝试使用文件对象会自动失败。

所以我假设你不应该依赖垃圾收集器自动为你关闭文件,而只是手动/使用with

【讨论】:

  • 有趣的文档是 3.8 不同(参见docs.python.org/3.8/tutorial/inputoutput.html)我认为它只会在 GC 收集它时关闭是错误的,因为 Python 也有 ref 计数,它会在打开后删除文件对象(...).read() 立即。他们目前仍然建议使用 with 语句(尽管出于其他原因),我认为这很遗憾,因为您可以只用一行引用计数来做同样的事情。
  • 引用计数在pythonsee here中被命名为“主要垃圾收集算法”,所以说“它只有在GC收集它时才会关闭是错误的,因为Python也有ref计数”并不真正适用。我怀疑他们从文档中删除了 GC 引用,以进一步阻止人们依赖 GC 收集器来关闭文件
  • @FlyingTeller,我添加了最近(Python 3.8-3.10)文档的引用,它比以前的文档更强大。就我个人而言,我认为可以删除对 Python 2.7 的引用(它早就死了),但我不会冒昧地走这么远,让你来决定。
  • 顺便说一句:这个话题因为this question而变得活跃
  • @wovano 感谢您的更新。我认为我们可以保留 2.7 参考以保持完整性,因为最初的问题是关于 python 2.x 的。我将进行编辑以强调对于当前的 python 版本,文档中没有更多的参考表明你可以不用with 语句。 python 3.6 中的Python’s garbage collector will eventually destroy the object and close the open file for you 不再适用
【解决方案2】:

这取决于你做什么,看看这个description how it works

一般来说我会推荐使用文件的上下文管理器:

with open("foo", "r") as f:
    for line in f.readlines():
    # ....

类似于(用于基本理解):

file_context_manager = open("foo", "r").__enter__()
for line in file_context_manager.readlines():
    # ....
file_context_manager.__exit__()

第一个版本更具可读性,withstatement 自动调用 exit 方法(加上更多context handling)。 当with 语句的范围离开时,文件将自动关闭。

【讨论】:

  • "which is the same as" 是一个令人困惑的语句,因为 with 块最后会调用 __exit__(),而在 for 循环结束时没有保证清除
  • 您的第二个示例非常相同,因为您调用 __enter__ 但从不调用 __exit__
  • 行为仍然不完全相同。 PEP 343 中的规范给出了 with 块扩展的确切翻译,而且要复杂得多。
【解决方案3】:

我经常使用open 而不使用with,所以我进行了一些测试。对于测试,我使用 Python 3.9,所以我不是在说早期版本,但至少对于 3.9,我们不需要 with 来关闭干净的文件。

重击

 inotifywait -m "testfile"

python3.9

 lines=[line for line in open("testfile")]
 sleep(5)
 for line in lines:
    print(line)

观看inotifywait 窗口并运行python 脚本。在睡眠之前,最终事件将是CLOSE_NOWRITE,CLOSE,并且通过运行 python 脚本不会有来自该文件的其他事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多