設計されたPython with with with」ステートメントとは何ですか?
-
26-09-2019 - |
質問
私はパイソンに出会いました with
今日初めての声明。私は数ヶ月間Pythonを軽く使用してきましたが、その存在さえ知りませんでした!そのややあいまいな状態を考えると、私はそれが尋ねる価値があると思いました:
- Pythonとは何ですか
with
使用するように設計されたステートメント? - それを何のために利用しますか?
- 私が認識する必要があるゴッチャ、またはその使用に関連する一般的なアンチパターンはありますか?それがより良い使用である場合
try..finally
よりもwith
? - なぜもっと広く使用されないのですか?
- どの標準ライブラリクラスと互換性がありますか?
解決
私はこれが私の前に他のユーザーによってすでに答えられていると信じているので、私はそれを完全性のためだけに追加するだけです:
with
ステートメントは、共通の準備とクリーンアップタスクをカプセル化することにより、例外処理を簡素化します。 コンテキストマネージャー. 。詳細はにあります PEP 343. 。たとえば、open
ステートメントはそれ自体がコンテキストマネージャーです。これにより、ファイルを開くことができます。実行がコンテキストにある限り、開いたままにしておくことができます。with
あなたがそれを使用した場所で、あなたがコンテキストを離れたらすぐにそれを閉じます、あなたが例外のためにまたは通常の制御フローの間にそれを離れたかどうかに関係なく。with
したがって、ステートメントは Raiiパターン C ++で:一部のリソースはwith
声明とあなたが離れるときにリリースされますwith
環境。いくつかの例は次のとおりです。使用してファイルを開く
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.stdout
とsys.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つの興味深い講義をお勧めします。
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()を呼び出してファイルを閉じる必要はありません