用Python读取整个文件

tMC*_*tMC 333 python file-io filehandle

如果你读取整个文件,content = open('Path/to/file', 'r').read()文件句柄是否保持打开状态直到脚本退出?是否有更简洁的方法来读取整个文件?

Sin*_*ion 537

这个问题的答案在某种程度上取决于特定的python实现.

要了解这是什么,请特别注意实际file对象.在您的代码中,该对象仅在表达式中被提及一次,并且在read()调用返回后立即变得不可访问.

这意味着文件对象是垃圾.唯一剩下的问题是"垃圾收集器什么时候收集文件对象?".

在使用引用计数器的CPython中,会立即注意到这种垃圾,因此会立即收集它.对于其他python实现,这通常不正确.

为确保文件已关闭,更好的解决方案是这种模式:

with open('Path/to/file', 'r') as content_file:
    content = content_file.read()
Run Code Online (Sandbox Code Playgroud)

在块结束后将立即关闭文件; 即使发生异常.

编辑:为它添加一个更好的点:

除了file.__exit__()with上下文管理器设置中"自动"调用之外,自动调用的唯一其他方法file.close()(即,除了自己明确调用之外)是通过file.__del__().这引出了我们什么时候__del__()被召唤的问题?

正确编写的程序不能假定终结器将在程序终止之前的任何时刻运行.

- http://blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx

特别是:

对象永远不会被明确销毁; 然而,当它们变得无法到达时,它们可能被垃圾收集.允许实现推迟垃圾收集或完全省略垃圾收集 - 只要没有收集到仍然可以访问的对象,实现垃圾收集的实现方式就是如此.

[...]

CPython目前使用带有(可选)延迟检测循环链接垃圾的引用计数方案,它会在大多数对象无法访问时立即收集,但不保证收集包含循环引用的垃圾.

- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types

(强调我的)

但正如它所暗示的那样,其他实现可能还有其他行为.举个例子,PyPy 6个不同的垃圾收集实现!

  • 有一段时间,没有其他Python实现; 但依赖于实现细节并不是真正的Pythonic. (23认同)
  • @jgmjgm 它更可靠,因为 `with foo() as f: [...]` 基本上与 `f = foo()`、`f.__enter__()`、[...] 和 `f.__enter__()` 相同。 __exit__()` *处理异常*,以便始终调用 `__exit__`。所以文件总是被关闭。 (3认同)
  • @jgmjgm 正是因为这 3 个问题,GC 不可预测,`try`/`finally` 繁琐,以及 `with` 解决的清理处理程序非常普遍无用。“显式关闭”和“用`with`管理”之间的区别在于即使抛出异常也会调用退出处理程序。您可以将 `close()` 放在 `finally` 子句中,但这与使用 `with` 没有太大区别,有点混乱(3 行而不是 1 行),并且更难做到恰到好处。 (2认同)

Eya*_*vin 81

您可以使用pathlib.

对于Python 3.5及更高版本:

from pathlib import Path
contents = Path(file_path).read_text()
Run Code Online (Sandbox Code Playgroud)

对于较低版本的Python,请使用pathlib2:

$ pip install pathlib2
Run Code Online (Sandbox Code Playgroud)

然后:

from pathlib2 import Path
contents = Path(file_path).read_text()
Run Code Online (Sandbox Code Playgroud)

这是实际的read_text 实现:

def read_text(self, encoding=None, errors=None):
    """
    Open the file in text mode, read it, and close the file.
    """
    with self.open(mode='r', encoding=encoding, errors=errors) as f:
        return f.read()
Run Code Online (Sandbox Code Playgroud)