明确关闭文件重要吗?


149

在Python中,如果您不调用即可打开文件close(),或者不使用try- finally或“ with”语句而关闭文件,这是问题吗?还是依靠Python垃圾回收来关闭所有文件作为一种编码实践就足够了?例如,如果这样做:

for line in open("filename"):
    # ... do stuff ...

...这是一个问题,因为文件永远无法关闭,并且可能发生阻止文件关闭的异常吗?还是for由于文件超出范围而肯定会在声明结束时将其关闭?


13
文件在块末尾不会超出范围for。它的引用计数将为零,从而使其自动关闭,但是只有函数,类和模块定义了Python中的作用域,而没有其他复合语句。
2011年

18
除非有问题,否则这不是问题。在操作系统级别,脚本退出时将关闭该脚本打开的所有文件,因此您不必担心在一次性工具脚本中关闭文件。但是,进程对它们可以维护的打开文件的数量有限制,因此,长期存在或复杂的脚本可能需要格外小心。无论如何,关闭文件都是一个好习惯。
罗素·博罗戈夫

3
@agf:您是对的,该文件不会超出范围,但这与for块和函数/类/模块之间的区别无关。比这要简单得多:对象没有作用域,只有名称有作用域。没有引用此对象的名称,因此这里没有任何东西可以留在范围内或超出范围。
最大

@max我的评论正在纠正他的假设,即for循环与某个范围相关联,并提到该文件由于完全不同的原因而被关闭。它没有涉及Python的作用域,因为它在这里无关紧要。
2012年

@max有一个隐式引用,其范围仅限于for循环...这是语义的一个论点
Peter R

Answers:


126

在您的示例中,不能保证在解释器退出之前关闭文件。在当前版本的CPython中,该文件将在for循环结束时关闭,因为CPython使用引用计数作为其主要的垃圾收集机制,但这是实现细节,而不是语言的功能。不能保证其他Python实现会以这种方式工作。例如,IronPython,PyPy和Jython不使用引用计数,因此不会在循环结束时关闭文件。

依靠CPython的垃圾回收实现是一个坏习惯,因为它使您的代码可移植性降低。如果使用CPython,则可能不会发生资源泄漏,但是,如果切换到不使用引用计数的Python实现,则需要遍历所有代码并确保正确关闭了所有文件。

作为示例,请使用:

with open("filename") as f:
     for line in f:
        # ... do stuff ...

8
使用with open() as f完成后,使用会自动关闭文件吗?
罗汉

24
@Rohan是的,这是小魔的with声明提供,当然这个神奇的工作对象必须具有特殊的方法__enter__,并__exit__在后者的对象做的close任何其他清理的东西,需要在该完成with声明的结尾...
Copperfield'Mar

1
仅供参考:此答案仅说明“何时关闭”,而没有说明“如果保持打开状态会怎样”。对于后者,请阅读“如果文件保持打开状态会发生什么?” 在这个答案部分(askubuntu.com/questions/701491/...
RayLuo

此外,不关闭文件可能会导致文件被截断,因为文件内容尚未刷新。
Erwan Legrand

因此,如果我不关闭文件,一旦程序停止运行,是否可以确保我恢复内存?还是我实际上必须退出整个口译员?
Pro Q

22

有些Python在不再被引用时会自动关闭文件,而其他Python不会,并且在Python解释器退出时由O / S来关闭文件。

即使对于将为您关闭文件的Python,也无法保证时间:可能是立即执行,也可能是秒/分钟/小时/天之后。

因此,尽管您使用的Python可能不会遇到问题,但绝对不要将文件保持打开状态。实际上,在cpython 3中,您现在会得到警告,如果您不这样做,系统必须为您关闭文件。

道德:自己清理。:)


9
当不再在CPython中引用文件时,文件将关闭,但这不是语言功能。如果是这样,您可以很高兴地依靠它。
彼得·格雷厄姆

9

尽管在这种特殊情况下使用这种构造是相当安全的,但仍需注意一些概括这种做法的注意事项:

  • 运行可能会用完文件描述符,尽管这不太可能,想象一下找到这样的错误
  • 您可能无法在某些系统上删除该文件,例如win32
  • 如果您运行的不是CPython,则不知道何时关闭文件
  • 如果以写或读写模式打开文件,则不知道何时刷新数据

3

该文件确实会收集垃圾,因此已关闭。GC将确定关闭的时间,而不是您。显然,这不是推荐的做法,因为如果您没有在使用完文件后立即关闭文件,则可能会达到打开文件句柄的限制。如果在您的那个for循环中打开更多文件而让它们挥之不去怎么办?


但是,如果您在该for循环中打开了其他文件,则无论是否显式关闭其中任何一个文件,仍然会同时打开多个文件。您是说文件超出范围时不一定要立即对其进行垃圾收集,因此,如果明确地将其关闭,则会更快地将其关闭?当发生异常时(当您与/ try-finally一起使用或不与之一起使用时)怎么办?
user553702 2011年

1
在CPython中,引用计数将导致在for语句后收集它-您不必等待下一次垃圾收集运行。
2011年

3

嗨,当您要在同一python脚本中使用文件描述符时,关闭文件描述符非常重要。经过很长时间的调试之后,我今天才意识到。原因是仅在关闭文件描述符后,内容才会被编辑/删除/保存,并且对文件的更改也会受到影响!

因此,假设您遇到的情况是将内容写入新文件,然后不关闭fd而在另一个读取其内容的shell命令中使用该文件(而非fd)。在这种情况下,您将无法按预期获得shell命令的内容,并且如果尝试调试,将很难找到该错误。您也可以在我的博客条目http://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.html中阅读更多内容


1

在I / O过程中,数据被缓冲:这意味着在将数据写入文件之前将其保留在一个临时位置。

Python不会刷新缓冲区(即,将数据写入文件),直到确定完成写入为止。一种方法是关闭文件。

如果您在不关闭的情况下写入文件,则数据将不会写入目标文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.