web-dev-qa-db-ja.com

Pythonでファイル全体を読む

content = open('Path/to/file', 'r').read()でファイル全体を読むと、スクリプトが終了するまでファイルハンドルは開いたままになりますか?ファイル全体を読むためのもっと簡潔な方法はありますか?

293
tMC

その質問に対する答えは、特定のpython実装に多少依存します。

これが何なのかを理解するために、実際のfileオブジェクトに特に注意を払ってください。あなたのコードでは、そのオブジェクトは式の中で一度だけ記述され、read()呼び出しが戻った直後にアクセスできないようになります。

これはファイルオブジェクトがゴミであることを意味します。残っている唯一の質問は、「ガベージコレクタがいつファイルオブジェクトを集めるのか」ということです。

参照カウンタを使用するCPythonでは、この種のゴミはすぐに気づかれるので、すぐに収集されます。これは一般的に他のpython実装には当てはまりません。

ファイルが閉じられていることを確認するためのより良い解決策は、次のパターンです。

with open('Path/to/file', 'r') as content_file:
    content = content_file.read()

これは、ブロックが終了した直後に常にファイルを閉じます。例外が発生しても。

編集:それに細かい点を置くために:

withコンテキストマネージャ設定で「自動的に」呼び出されるfile.__exit__()以外の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の異なるガベージコレクションの実装を持っています

pathlib を使用できます。

Python 3.5以上の場合

from pathlib import Path
contents = Path(file_path).read_text()

それより前のバージョンのPythonでは、 pathlib2 を使用します。

$ pip install pathlib2

その後:

from pathlib2 import Path
contents = Path(file_path).read_text()

これが実際の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()
60
Eyal Levin