Python の「with」ステートメントは何のために設計されているのですか? 質問する

Python の「with」ステートメントは何のために設計されているのですか? 質問する

with今日初めてPython ステートメントに出会いました。数か月間 Python を軽く使っていましたが、その存在すら知りませんでした。あまり知られていない状況なので、質問してみる価値があると思いました。

  1. Pythonwithステートメントは何の目的で設計されているのでしょうか?
  2. あなたはそれを何に使っているの?
  3. 知っておく必要のある落とし穴や、その使用に関連する一般的なアンチパターンはありますか?try..finallyよりもそれを使用する方が良いケースはありますかwith?
  4. なぜもっと広く使われないのでしょうか?
  5. どの標準ライブラリクラスが互換性がありますか?

ベストアンサー1

  1. これはすでに他のユーザーが回答していると思うので、完全性のために追加します。このwithステートメントは、一般的な準備とクリーンアップタスクをいわゆるコンテキストマネージャー詳細は以下をご覧ください。ペップ343たとえば、openステートメントはそれ自体がコンテキストマネージャであり、ファイルを開き、それwithを使用したステートメントのコンテキスト内で実行されている限り開いたままにし、例外のためまたは通常の制御フロー中にコンテキストを離れたかどうかに関係なく、コンテキストを離れるとすぐにファイルを閉じることがwithできます。したがって、ステートメントは、RAIIパターンC++ の場合: 一部のリソースはステートメントによって取得されwith、コンテキストを離れるときに解放されますwith

  2. 例としては、 を使用してファイルを開く、 ( はのインスタンス)with open(filename) as fp:を使用してロックを取得するなどが挙げられます。のデコレータを使用して、独自のコンテキスト マネージャーを構築することもできます。たとえば、現在のディレクトリを一時的に変更してから元の場所に戻る必要があるときに、私はこれをよく使用します。with lock:lockthreading.Lockcontextmanagercontextlib

    from contextlib import contextmanager
    import os
    
    @contextmanager
    def working_directory(path):
        current_dir = os.getcwd()
        os.chdir(path)
        try:
            yield
        finally:
            os.chdir(current_dir)
    
    with working_directory("data/stuff"):
        # do something within data/stuff
    # here I am back again in the original working directory
    

    以下は、、およびを一時的に他のファイル ハンドルにリダイレクトし、後で復元するsys.stdin別の例です。sys.stdoutsys.stderr

    from contextlib import contextmanager
    import sys
    
    @contextmanager
    def redirected(**kwds):
        stream_names = ["stdin", "stdout", "stderr"]
        old_streams = {}
        try:
            for sname in stream_names:
                stream = kwds.get(sname, None)
                if stream is not None and stream != getattr(sys, sname):
                    old_streams[sname] = getattr(sys, sname)
                    setattr(sys, sname, stream)
            yield
        finally:
            for sname, stream in old_streams.iteritems():
                setattr(sys, sname, stream)
    
    with redirected(stdout=open("/tmp/log.txt", "w")):
         # these print statements will go to /tmp/log.txt
         print "Test entry 1"
         print "Test entry 2"
    # back to the normal stdout
    print "Back to normal stdout again"
    

    最後に、一時フォルダーを作成し、コンテキストを離れるときにそれをクリーンアップする別の例を示します。

    from tempfile import mkdtemp
    from shutil import rmtree
    
    @contextmanager
    def temporary_dir(*args, **kwds):
        name = mkdtemp(*args, **kwds)
        try:
            yield name
        finally:
            shutil.rmtree(name)
    
    with temporary_dir() as dirname:
        # do whatever you want
    

おすすめ記事