ファイルを明示的に閉じることは重要ですか?


149

Pythonでは、を呼び出さずにファイルを開くか、ファイルをclose()閉じてtry- finallyまたは " with"ステートメントを使用しない場合、これは問題ですか?それとも、すべてのファイルを閉じるためにPythonガベージコレクションに依存するコーディングプラクティスとして十分ですか?たとえば、これを行う場合:

for line in open("filename"):
    # ... do stuff ...

...これはファイルを閉じることができず、ファイルを閉じるのを妨げる例外が発生する可能性があるため、これは問題ですか?またはfor、ファイルが範囲外になるため、ステートメントの最後に確実に閉じられますか?


13
ファイルは、ブロックの最後で範囲外になりませfor。その参照カウントはゼロになり、自動的に閉じられますが、Pythonでスコープを定義するのは関数、クラス、およびモジュールのみであり、他の複合ステートメントは定義しません。
agf

18
それが問題でなければ、それは問題ではありません。OSレベルでは、スクリプトによって開かれたファイルはスクリプトの終了時に閉じられるため、使い捨てツールスクリプトでファイルを閉じることを心配する必要はありません。ただし、プロセスには、維持できるオープンファイルの数に制限があるため、長期間有効なスクリプトや複雑なスクリプトには、さらに注意が必要になる場合があります。いずれにしても、ファイルを閉じることは良い習慣です。
ラッセルボロゴーブ2011

3
@agf:ファイルがスコープ外にならないのは正しいですが、forブロックと関数/クラス/モジュールの区別とは関係ありません。それよりもはるかに単純です。オブジェクトにはスコープがなく、名前だけがあります。このオブジェクトを参照する名前はないため、ここにスコープ内に留まったり、スコープ外に出たりすることはありません。
最大

@max私のコメントは、forループに関連付けられたスコープがあるという彼の仮定を修正し、ファイルがまったく異なる理由で閉じられることを述べています。ここでは関係がないため、Pythonのスコープについては説明しません。
agf

@maxそのforループをスコープとする暗黙の参照があります...これはセマンティクスの引数です
Peter R

回答:


126

あなたの例では、インタプリタが終了する前にファイルが閉じられることが保証されていません。CPythonの現在のバージョンでは、CPythonは参照カウントを主要なガベージコレクションメカニズムとして使用するため、ファイルはforループの最後で閉じられますが、これは実装の詳細であり、言語の機能ではありません。Pythonの他の実装は、このように動作することが保証されていません。たとえば、IronPython、PyPy、およびJythonは参照カウントを使用しないため、ループの最後でファイルを閉じません。

コードの移植性が低下するため、CPythonのガベージコレクションの実装に依存することはお勧めできません。CPythonを使用している場合はリソースリークがない可能性がありますが、参照カウントを使用しないPython実装に切り替える場合は、すべてのコードを調べて、すべてのファイルが適切に閉じられていることを確認する必要があります。

あなたの例では:

with open("filename") as f:
     for line in f:
        # ... do stuff ...

8
を使用with open() as fすると、ファイルは完了後に自動的に閉じますか?
Rohan

24
@Rohanはい、それはそれを少し魔法であるwith文は提供しますが、この魔法は、オブジェクトを動作させるために、もちろん、特別なメソッドを持っている必要があります__enter____exit__、後者にオブジェクトが行うcloseと必要性がで行われることを、他のクリーンアップのものwith声明の終わり...
Copperfield 2016年

1
参考:この回答は「いつ閉まるか」についてのみ説明し、「開いたままの場合」については説明していません。後者については、「ファイルを開いたままにするとどうなりますか?」を読んでください。この答え(中一部askubuntu.com/questions/701491/...
RayLuo

さらに、ファイルの内容がフラッシュされていないため、ファイルを閉じないとファイルが切り捨てられる可能性があります。
Erwan Legrand 2017年

ファイルを閉じない場合、プログラムが実行を停止すると、メモリは確実に回復しますか?それとも、通訳全体をやめなければならないのですか?
Pro Q

22

一部のPythonは参照されなくなったときにファイルを自動的に閉じますが、Pythonインタープリターが終了したときにファイルを閉じるのはO / Sに依存しないものもあります。

ファイルを閉じるPythonの場合でも、タイミングは保証されていません。即時の場合もあれば、秒/分/時間/日後の場合もあります。

そのため、使用しているPythonで問題が発生することはないかもしれませんが、ファイルを開いたままにしておくことは間違いなくお勧めできません。実際、cpython 3では、実行しなかった場合にシステムがファイルを閉じる必要があるという警告が表示されます。

道徳:自分の後を片付けなさい。:)


9
CPythonで参照されなくなったファイルは閉じられますが、これは言語機能ではありません。もしそうなら、あなたはとても喜んでそれに頼ることができます。
Peter Graham

9

この特定のケースでそのような構成を使用することは非常に安全ですが、そのような慣行を一般化するためのいくつかの警告があります:

  • runは、ファイル記述子が不足する可能性がありますが、そのようなバグを探すことは考えられません
  • 一部のシステム、たとえばwin32では、上記のファイルを削除できない場合があります。
  • CPython以外のものを実行する場合、ファイルがいつ閉じられるかわかりません
  • ファイルを書き込みモードまたは読み取り/書き込みモードで開いた場合、データがフラッシュされるタイミングがわかりません

3

ファイルはガベージコレクションされているため、閉じられます。GCは、ユーザーではなく、いつ閉じるかを決定します。明らかに、ファイルの使用を終了した直後にファイルを閉じないと、オープンファイルハンドルの制限に達する可能性があるため、これは推奨される方法ではありません。forあなたのループ内で、より多くのファイルを開いて、それらを長引かせておくとどうなりますか?


ただし、そのforループ内で他のファイルを開いた場合、明示的に閉じたかどうかに関係なく、同時に複数のファイルが開かれる可能性があります。ファイルがスコープ外になるとすぐにファイルがガベージコレクションされるとは限らないので、明示的に実行するとファイルはすぐに閉じられると言っていますか?例外が発生した場合(with / try-finallyを使用した場合と使用しない場合)はどうですか?
user553702 2011

1
CPythonでは、参照カウントによりforステートメントの後に収集されます-次のガベージコレクションの実行を待つ必要はありません。
agf

3

こんにちは同じpythonスクリプトでコンテンツを使用する場合は、ファイル記述子を閉じることが非常に重要です。私は今日、長い間デバッグに悩まされた後で気づきました。その理由は、ファイル記述子を閉じて変更がファイルに影響を与えた後でないと、コンテンツが編集/削除/保存されないためです。

したがって、新しいファイルにコンテンツを書き込み、fdを閉じずに、そのコンテンツを読み取る別のシェルコマンドでそのファイル(fdではなく)を使用している状況があるとします。この状況では、期待どおりにシェルコマンドのコンテンツを取得できず、デバッグしようとしてもバグを簡単に見つけることができません。また、私のブログエントリhttp://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.htmlでも詳細を読むことができます


1

I / Oプロセス中、データはバッファリングされます。つまり、データはファイルに書き込まれる前に一時的な場所に保持されます。

Pythonは、書き込みが確実に完了するまで、バッファをフラッシュしません(つまり、ファイルにデータを書き込みません)。これを行う1つの方法は、ファイルを閉じることです。

閉じずにファイルに書き込むと、データはターゲットファイルに書き込まれません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.