将open call作为参数传递给另一个函数后,文件对象是否已关闭?

时间:2013-10-15 02:44:05

标签: python

如果我只想使用一个file对象,通常我会在完成后使用with块或显式关闭file对象,因为关闭文件似乎是正确的事情:

with open('filename','r') as f:
    x = dosomething(f)

f = open('filename','r')
x = dosomething(f)
f.close()

但是,我看到人们使用将open的调用直接传递给函数而不将输出保存到任何变量,从而无法明确关闭:

x = dosomething(open('filename','r'))

所以,其中任何一个都是真的,

  1. 以某种方式关闭未命名的文件对象
  2. 没关系,关闭文件没关系
  3. 或者这是一种不好的做法?

    另外,如果我允许文件读/写,答案是否会改变?

    要明确,dosomething可能类似于np.array()for i in f.readlines()

1 个答案:

答案 0 :(得分:12)

这是一种糟糕的做法。它与开放模式(读,写,读+写,附加,二进制模式,文本模式......)无关。

在CPython中,"它几乎总是有效的"因为文件对象在变为垃圾(无法访问)时会自动关闭,而CPython的引用计数通常在它变为垃圾后很快收集(非循环)垃圾。

但依靠这确实是不好的做法。

例如,如果dosomething(f)在返回之前运行了一个小时,则文件对象在整个时间内保持打开的可能性非常大。

注意:在某些情况下,dosomething(f)可能会被编码为显式关闭传入的文件对象本身。在那些情况下,它并非糟糕的做法; - )

后来:我经常看到的相关事情就是:

data = open(file_path).read()

在CPython中,由于CPython的引用计数,语句完成时,未命名的文件对象会立即被垃圾收集(因此也会被关闭)。当他们将代码移动到不同的Python实现时,人们会感到惊讶,并且获得OS"太多的打开文件!"投诉。嘿 - 服务对了; - )

示例:

open("Output.txt", "w").write("Welcome")
print open("Output.txt").read()

打印

Welcome
在CPython中

,因为当第一个语句结束时,第一个语句中的未命名文件对象立即被垃圾收集(并关闭)。

可是:

output = open("Output.txt", "w")
output.write("Welcome")
print open("Output.txt").read()

可能在CPython中打印一个空行。在这种情况下,文件对象绑定到名称(output),因此在第二个语句完成时收集垃圾(从理论上讲,智能实现可以检测到output永远不会再使用,垃圾收集,但CPython不会。)

"欢迎"可能仍在文件的内存缓冲区中,因此尚未写入磁盘。所以第三个语句可能找到一个空文件,并且什么都不打印。

在Python的其他实现中,两个示例都可以打印空行。