使用 pathlib 模块关闭文件的推荐方法?

Recommended way of closing files using pathlib module?

从历史上看,我一直使用以下方法读取 python 中的文件:

with open("file", "r") as f:
    for line in f:
        # do thing to line

这仍然是推荐的方法吗?使用以下内容是否有任何缺点:

from pathlib import Path

path = Path("file")
for line in path.open():
    # do thing to line

我找到的大多数参考文献都使用 with 关键字打开文件,以便于不必显式关闭文件。这适用于此处的迭代器方法吗?

with open() docs

Pathlib 是面向对象的方式来操作文件系统路径。

使用 pathlib 模块打开文件的推荐方法是使用上下文管理器:

p = Path("my_file.txt")

with p.open() as f:
    f.readline()

这确保在使用后关闭文件。


在您提供的两个示例中,您没有关闭文件,因为您打开它们 inplace

由于 p.open() returns 文件对象,您可以通过分配它并检查属性 closed 来测试它,如下所示:

from pathlib import Path

path = Path("file.txt")

# Open the file pointed by this path and return a file object, as
# the built-in open() function does.
f = path.open()
for line in f:
    # do some stuff

print(f.closed)  # Evaluates to False.

请记住,Path 对象用于处理文件系统路径。就像 built-in library of Python, there is an open 方法一样,但在 Path 对象中没有关闭。

.close 位于由内置 open 或使用 Path 对象的打开方法返回的文件句柄中:

>>> from pathlib import Path
>>> p=Path(some_file)
>>> p
PosixPath('/tmp/file')

您可以使用内置的 open 函数或 Path 对象中的 open 方法打开该 Path 对象:

>>> fh=open(p)    # open built-in function
>>> fh
<_io.TextIOWrapper name='/tmp/file' mode='r' encoding='UTF-8'>
>>> fh.close()

>>> fh=p.open()   # Path open method which aliases to os.open
>>> fh
<_io.TextIOWrapper name='/tmp/file' mode='r' encoding='UTF-8'>
>>> fh.close()

您可以查看 pathlib on Github 的源代码,了解 pathlib 的作者是如何在他们自己的代码中做到这一点的。

我观察到的是三件事之一。

到目前为止最常见的是使用 with:

from pathlib import Path 

p=Path('/tmp/file')

#create a file
with p.open(mode='w') as fi:
    fi.write(f'Insides of: {str(p)}')

# read it back and test open or closed
with p.open(mode='r') as fi:
    print(f'{fi.read()} closed?:{fi.closed}')

# prints 'Insides of: /tmp/file closed?:False'

您可能知道,在 with 块的末尾调用 __exit__ 方法。对于文件,这意味着文件已关闭。这是 pathlib 源代码中最常见的方法。

其次,您还可以在源代码中看到,pathlib 对象维护进入和退出状态以及文件打开和关闭的标志。然而,os.close 函数并未明确调用。您可以使用 .closed 访问器检查该状态。

fh=p.open()
print(f'{fh.read()} closed?:{fh.closed}')
# prints Insides of: /tmp/file closed?:False    
# fi will only be closed when fi goes out of scope...
# or you could (and should) do fh.close()


with p.open() as fi:
    pass
print(f'closed?:{fi.closed}')   
# fi still in scope but implicitly closed at the end of the with bloc
# prints closed?:True

第三,在 cPython 上,当文件句柄超出范围时,文件将关闭。这不可移植或被认为 'good practice' 可以依赖,但通常是这样。在 pathlib 源代码中有这样的实例。

尚未提及的事情:如果您只想读取或写入一些文本(或字节),那么在使用 pathlib 时您不再需要显式使用上下文管理器:

>>> import pathlib
>>> path = pathlib.Path("/tmp/example.txt")
>>> path.write_text("hello world")
11
>>> path.read_text()
'hello world'
>>> path.read_bytes()
b'hello world'

打开文件以迭代行仍应使用 with 语句,原因与将上下文管理器与 open 一起使用的原因相同,如 the docs show:

>>> with path.open() as f:
...     for line in f:
...         print(line)
...
hello world