4

私は定期的にこの種のコードを見ます:

filecontent = open(thefilename).read()

この状況でによって作成されたファイル オブジェクトはどうなるのだろうかopen: 暗黙的に閉じられているのか、それともどこかで開いたままなのか?

4

1 に答える 1

12

この状況で open によって作成されたファイル オブジェクトはどうなるのだろうか?

誰もアクセスできなくなったことをガベージ コレクターが発見して破棄するまで開いたままになり、その時点でデストラクタによって閉じられます。

Python 言語は、それがいつ起こるかについて保証しません (もちろん、アクセスできなくなった後であることを除いて)。

ただし、CPython 実装 (2013 年 5 月の時点で 3.x で動作する唯一の実装であるため、おそらく使用している) は、ガベージ コレクションに参照カウント (およびサイクル検出器) を使用します。 (ある時点でサイクルに関与していない限り)、オブジェクトは破棄されます。

したがって、CPython では、ほとんどの場合、関数から戻るとすぐにファイルが閉じられ、新しい値がfilecontent、またはに割り当てられdel filecontentます。そして、多くのクイック&ダーティ コードがこれに依存しています。

しかし、Jython と IronPython は Java/.NET ガベージ コレクターに依存しています。Java/.NET ガベージ コレクターは、その場で追跡するのではなく、複雑で手の込んだ方法で定期的にガベージをチェックします。そのため、何かがいつ収集されるかについての保証はありません。また、PyPy には、構成方法に応じて複数のオプションがあります。

また、CPython でも、可視参照がなくなった後もガベージが残る可能性があります。たとえば、デバッガーで実行し、最終的に不可視参照になったことが原因です。または、ファイルが参照サイクルに関与していた場合、ファイルが閉じられないことがあります。

したがって、quick&dirty コード以外では、この動作に依存しないでください。基本的に、プログラムが終了するまでファイルを開いたままにしておくことが許容される場合は問題ありません。そうでなければ、それをしないでください。

これを行う正しい方法は、withステートメントを使用することです。

with open(thefilename) as f:
    filecontent = f.read()

これにより、ステートメントが終了f.close()するとすぐに が呼び出されることが保証されます。with

ときどき、人々はこれをワンライナーに変える方法を提案しますが、Guido は常に「with open(thefilename) as f: filecontent = f.read()すでにワンライナーです。それはちょっと悪いですが、あなたが提案しているものほど悪くはありません。 ."

しかし実際には、もっと良い答えがあります: それをラップする関数を書きます:

def read_whole_file(filename):
    with open(thefilename) as f:
        return f.read()

その後:

filecontent = read_whole_file(thefilename)

きれいで、簡潔で、読みやすい…「openすべてを GC に任せて」というハックの言い訳はありません。

于 2013-05-06T19:38:14.537 に答える