質問

私はパイソンに出会いました with 今日初めての声明。私は数ヶ月間Pythonを軽く使用してきましたが、その存在さえ知りませんでした!そのややあいまいな状態を考えると、私はそれが尋ねる価値があると思いました:

  1. Pythonとは何ですか with 使用するように設計されたステートメント?
  2. それを何のために利用しますか?
  3. 私が認識する必要があるゴッチャ、またはその使用に関連する一般的なアンチパターンはありますか?それがより良い使用である場合 try..finally よりも with?
  4. なぜもっと広く使用されないのですか?
  5. どの標準ライブラリクラスと互換性がありますか?
役に立ちましたか?

解決

  1. 私はこれが私の前に他のユーザーによってすでに答えられていると信じているので、私はそれを完全性のためだけに追加するだけです: with ステートメントは、共通の準備とクリーンアップタスクをカプセル化することにより、例外処理を簡素化します。 コンテキストマネージャー. 。詳細はにあります PEP 343. 。たとえば、 open ステートメントはそれ自体がコンテキストマネージャーです。これにより、ファイルを開くことができます。実行がコンテキストにある限り、開いたままにしておくことができます。 with あなたがそれを使用した場所で、あなたがコンテキストを離れたらすぐにそれを閉じます、あなたが例外のためにまたは通常の制御フローの間にそれを離れたかどうかに関係なく。 with したがって、ステートメントは Raiiパターン C ++で:一部のリソースは with 声明とあなたが離れるときにリリースされます with 環境。

  2. いくつかの例は次のとおりです。使用してファイルを開く with open(filename) as fp:, 、使用を使用してロックを取得します with lock: (どこ lock のインスタンスです threading.Lock)。また、 contextmanager からのデコレーター contextlib. 。たとえば、現在のディレクトリを一時的に変更してから、次の場所に戻る必要があるときに、これをよく使用します。

    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
    

他のヒント

2つの興味深い講義をお勧めします。

  • PEP 343 「with」ステートメント
  • Effbot Pythonの「With」ステートメントを理解する

1. with ステートメントは、コンテキストマネージャーによって定義されたメソッドを使用してブロックの実行をラップするために使用されます。これにより、共通が可能になります try...except...finally 便利な再利用のためにカプセル化される使用パターン。

2.あなたは次のようなことをすることができます:

with open("foo.txt") as foo_file:
    data = foo_file.read()

また

from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
   do_something()

または(Python 3.1)

with open('data') as input_file, open('result', 'w') as output_file:
   for line in input_file:
     output_file.write(parse(line))

また

lock = threading.Lock()
with lock:
    # Critical section of code

3.ここにアンチパッターンは表示されません。
引用 Pythonに飛び込みます:

試してみてください。との方が良いです。

4.私はそれが使用するプログラマーの習慣に関連していると思います try..catch..finally 他の言語からの声明。

Python with ステートメントは、の言語サポートが組み込まれています Resource Acquisition Is Initialization C ++で一般的に使用されるIdiom。安全な買収とオペレーティングシステムリソースのリリースを許可することを目的としています。

with ステートメントは、スコープ/ブロック内でリソースを作成します。ブロック内のリソースを使用してコードを書き込みます。ブロックが終了すると、ブロック内のコードの結果に関係なく、リソースがきれいにリリースされます(つまり、ブロックが正常に終了するかどうか、または例外のために)。

Pythonライブラリ内の多くのリソースは、 with 声明など、すぐに使用できます。ただし、誰でも、適切に文書化されたプロトコルを実装することにより、ステートメントで使用できるリソースを作成できます。 PEP 0343

ファイル、ネットワーク接続、ロックなど、明示的に放棄する必要があるアプリケーションでリソースを取得するたびに使用してください。

アンチパッターンの例は、 with ループ内では、 with ループの外側

例えば

for row in lines:
    with open("outfile","a") as f:
        f.write(row)

vs

with open("outfile","a") as f:
    for row in lines:
        f.write(row)

最初の方法は、それぞれのファイルを開閉することです row これは、ファイルを一度だけ開いて閉じる2番目の方法に比べてパフォーマンスの問題を引き起こす可能性があります。

繰り返しますが、私は私の最も便利なユースケースを追加します with ステートメント。

私は多くの科学的コンピューティングをしています、そしていくつかの活動のために私は Decimal 任意の精度計算のためのライブラリ。私のコードの一部は高精度が必要であり、他のほとんどの部分では、より少ない精度が必要です。

デフォルトの精度を低い数値に設定してから使用します with いくつかのセクションに対してより正確な答えを得るには:

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

私はこれを多くの幾何学的検定で多く使用します。これには、大量のフォームファクタリリアルを分割する必要があります。ゲノムスケールの計算を行う場合、丸めのエラーとオーバーフローエラーに注意する必要があります。

見る PEP 343 -'with'ステートメント, 、最後にセクションの例があります。

... Python言語に「with "with" with "with" with "with" with "with" with "with fort butter try/最終的なステートメントの標準的な使用)。

ポイント1、2、および3は合理的によくカバーされています:

4: 比較的新しいもので、python2.6+(またはpython2.5でのみ利用可能です from __future__ import with_statement)

withステートメントは、いわゆるコンテキストマネージャーと連携します。

http://docs.python.org/release/2.5.2/lib/typecontextmanager.html

アイデアは、「with」ブロックを残した後、必要なクリーンアップを行うことにより、例外処理を簡素化することです。 Pythonビルトインの一部は、すでにコンテキストマネージャーとして機能しています。

すぐにボックスのサポートの別の例、そしてあなたが組み込みの方法に慣れているときに最初は少し困惑するかもしれない例 open() 振る舞います connection 次のような一般的なデータベースモジュールのオブジェクト

connection オブジェクトはコンテキストマネージャーであるため、すぐに使用できます。 with-statement, しかし、上記を使用する場合、次のことに注意してください。

いつ with-block 例外を除いて、またはそれなしで終了します。 接続が閉じられていません. 。の場合 with-block 例外を除いて終了すると、トランザクションがロールバックされます。そうしないと、トランザクションがコミットされます。

これは、プログラマーが接続自体を閉じるように注意する必要があることを意味しますが、接続を取得し、複数で使用することができます with-statements, 、に示されているように psycopg2ドキュメント:

conn = psycopg2.connect(DSN)

with conn:
    with conn.cursor() as curs:
        curs.execute(SQL1)

with conn:
    with conn.cursor() as curs:
        curs.execute(SQL2)

conn.close()

上記の例では、次のことに注意してください cursor のオブジェクト psycopg2 また、コンテキストマネージャーです。動作に関する関連文書から:

a cursor 終了します with-block 閉じられており、最終的に関連するリソースをリリースします。取引の状態は影響を受けません。

一般的にPythonで」ステートメントは、ファイルを開き、ファイルに存在するデータを処理し、close()メソッドを呼び出すことなくファイルを閉じるために使用されます。 「with」ステートメントにより、クリーンアップアクティビティを提供することにより、例外処理が簡単になります。

の一般的な形式:

with open(“file name”, “mode”) as file-var:
    processing statements

ノート: file-var.close()でclose()を呼び出してファイルを閉じる必要はありません

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top