4

当我在 IPython3 shell 中使用这段代码时

 >>>data = open('file').read()

然后检查打开的文件描述符:

 lsof | grep file

我发现空列表

当我使用这个时:

>>>open('file')

lsof显示两个项目。问题是为什么第一个操作关闭 fd 而第二个没有?我认为垃圾收集器必须删除没有引用的文件对象。

当我重新分配值时,我知道解释器中的 '_' var

>>>111
>>>_
111

但描述符保持打开状态。当我重复

>>>open('file')

n 次有 2 * n 个打开的描述符

4

3 回答 3

4

在第二个示例中,文件句柄由交互式解释器变量保留_,它允许您访问最后评估的表达式。如果您评估另一个表达式,例如1+1,您会注意到该文件不再报告lsof为打开。

正如 Mike Byers 所指出的,这种行为是特定于 CPython 的,甚至是特定于如何使用文件对象的精确环境。要确保无论代码如何执行都关闭文件,请使用以下with语句:

with open('file') as fp:
    data = fp.read()
于 2012-11-09T20:39:26.890 回答
2

默认的 Python 实现同时使用垃圾收集和引用计数。在您的第一个示例中,文件对象的引用计数降至零,因此即使在垃圾收集器运行之前它也会立即关闭。

第二个版本等价于:

_ = open('file')

由于该文件仍被引用,_因此在您运行另一个命令之前它仍然有效。

请注意,此行为特定于 CPython。IronPython 等其他实现可能不会那么快地关闭文件,因此您应该在使用完文件后真正关闭它们。一个很好的方法是使用with 语句

with open('file') as f:
    data = f.read()

有关的

于 2012-11-09T20:32:59.933 回答
2

这是因为您使用的交互式解释器保留了对返回的最后一个对象的隐式引用。该引用名为_.

Python2> open("/etc/hosts") 
<open file '/etc/hosts', mode 'r' at 0xf2c390> 
Python2> _ 
<open file '/etc/hosts', mode 'r' at 0xf2c390>

所以当你看它时它仍然是“活的”。做点别的:

Python2> max(0,1)
1

该文件现在已关闭,因为它不再被引用。

但这是一个很好的例子,说明了为什么您应该明确关闭您真正想要关闭的文件。

于 2012-11-09T20:40:59.950 回答