with
ステートメントまたはコンテキストマネージャーは、リソースを支援するためにあります(ただし、さらに多くの目的で使用される場合があります)。
書き込み用にファイルを開いたとしましょう。
f = open(path, "w")
これで、開いているファイルハンドルができました。ファイルの処理中は、他のプログラムがファイルに書き込むことはできません。他のプログラムに書き込めるようにするには、ファイルハンドルを閉じる必要があります。
f.close()
しかし、ファイルを閉じる前にエラーが発生しました:
f = open(path, "w")
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
f.close()
ここで何が起こるかというと、ファイルを開いたままにして、関数またはプログラム全体が終了するということです。(CPythonは終了時にハンドルをクリーンアップし、ハンドルはプログラムと一緒に解放されますが、それを当てにするべきではありません)
withステートメントは、インデントを残すとすぐにファイルハンドルを閉じることを保証します。
with open(path, "w") as f:
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
# In here the file is already closed automatically, no matter what happened.
with
ステートメントは、さらに多くのことに使用できます。例えば:threading.Lock()
lock = threading.Lock()
with lock: # Lock is acquired
do stuff...
# Lock is automatically released.
コンテキストマネージャーで行われるほとんどすべてのことを行うことができますがtry: ... finally: ...
、コンテキストマネージャーは、より使いやすく、より快適で、より読みやすく、実装して使いやすいインターフェイスを提供します__enter__
。__exit__
コンテキストマネージャーの作成は、通常のクラスで実装することによって行われ__enter__()
ます__exit__()
。
__enter__()
コンテキストマネージャーが起動したときとコンテキストマネージャーが存在したときに何をすべきかを指示します(例外が発生した場合はメソッド__exit__()
に例外を与えます)__exit__()
コンテキストマネージャーを作成するためのショートカットは、contextlibにあります。ジェネレーターをコンテキストマネージャーとしてラップします。