文件已关闭吗?

时间:2013-05-06 19:36:59

标签: python file python-3.x

我经常看到这种代码:

filecontent = open(thefilename).read()

我想知道open在这种情况下创建的文件对象是什么:隐式关闭,还是在某处保持开放?

1 个答案:

答案 0 :(得分:12)

  

我想知道在这种情况下open会创建的文件对象是什么:它是隐式关闭的,还是在某个地方保持打开状态?

它一直保持打开状态,直到垃圾收集器发现任何人都无法访问它并销毁它,此时它被析构函数关闭。

Python语言不能保证何时会发生这种情况(当然,除非您不能再访问它,否则它将会出现。)

然而,CPython实现(您可能正在使用它,因为它是截至2013年5月唯一可用的3.x实现)使用引用计数(加上循环检测器)进行垃圾收集,这意味着只要最后一个引用消失了(除非它在某个时刻涉及一个循环),对象就会被破坏。

因此,在CPython中,在大多数情况下,文件将在您从函数返回后立即关闭,将新值分配给filecontentdel filecontent。许多快速和肮脏的代码都依赖于此。

但是Jython和IronPython依赖于Java / .NET垃圾收集器,它会以复杂和奇特的方式定期检查垃圾,而不是动态跟踪,因此无法确保何时收集任何内容。 PyPy有多种选择,具体取决于它的配置方式。

而且,即使在CPython中,在没有可见引用之后垃圾仍然存在,因为例如,你在调试器中运行它并最终得到一些不可见参考。或者,如果文件涉及参考周期,则永远不会关闭。

因此,除了快速和严格的代码之外,您不应该依赖此行为。基本上,如果在程序完成之前文件保持打开是可以接受的,那很好。否则,不要这样做。

正确的方法是使用with语句:

with open(thefilename) as f:
    filecontent = f.read()

这可以保证f.close()语句完成后立即调用with

每隔一段时间,人们就会建议一种方法将其变成一个单行,Guido总是会回答这样的话,“with open(thefilename) as f: filecontent = f.read()已经是一个单行。而且它有点不好,但不是很接近和你的建议一样糟糕。“

但实际上,还有一个更好的答案:编写一个包装它的函数:

def read_whole_file(filename):
    with open(thefilename) as f:
        return f.read()

然后:

filecontent = read_whole_file(thefilename)

干净,简洁,可读......“open”所有人都没有任何借口,让GC排除“黑客攻击”。