当我在IPython3 shell中使用此代码时
>>>data = open('file').read()
然后检查打开的文件描述符:
lsof | grep file
我找到空列表
当我使用它时:
>>>open('file')
lsof
显示两个项目。问题是为什么第一次操作关闭fd而第二次没有?我认为垃圾收集器必须删除没有引用的文件对象。
当我重新分配值
时,我知道解释器中的'_'var>>>111
>>>_
111
但描述符仍然存在。 当我重复
>>>open('file')
n次有2 * n个打开的描述符
答案 0 :(得分:4)
在第二个示例中,交互式解释器变量_
保留了文件句柄,允许您访问最后计算的表达式。如果您评估其他表达式,例如1+1
,则会注意lsof
不再将该文件报告为已打开。
正如迈克·拜尔斯所指出的,这种行为特定于CPython,甚至是关于如何使用文件对象的精确情况。无论代码如何执行,要确保文件已关闭,请使用with
语句:
with open('file') as fp:
data = fp.read()
答案 1 :(得分:2)
默认的Python实现使用垃圾收集和引用计数。在第一个示例中,文件对象的引用计数降为零,因此即使在垃圾收集器运行之前它也会立即关闭。
第二个版本相当于:
_ = open('file')
由于文件仍由_
引用,因此在您运行另一个命令之前它仍然有效。
请注意,此行为特定于CPython。其他实现(如IronPython)可能无法快速关闭文件,因此在使用完文件后应该真正关闭文件。一个很好的方法是使用with statement。
with open('file') as f:
data = f.read()
相关强>
答案 2 :(得分: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
该文件现已关闭,因为它不再被引用。
但这是一个很好的例子,说明为什么你应该明确地关闭你真正想要关闭的文件。