コンテキストマネージャーであるwithはどういう仕組で動いているのか?
ファイルのオープン・クローズでよく見かけるwith ですが、これがどうやって動いているのかを紹介します。
withはコンテキストマネージャーと呼ばれます。
コンテキスト = ”文脈 or 状況”
マネージャー = ”管理者”
状況をうまく管理してくれる奴ぐらいの意味です。
まずよく見かけるファイルを開いて中身を取り出す時に使うwith構文
with open('test.txt', 'r') as f:
print("1:", f.readlines())
print("2:", f.closed)
print("3:", f.closed)
1: ['text']
2: False
3: True
2: False
3: True
test.textには'text'という文字列一行からなるtxtファイルです。
f.closedでファイルオブジェクトの開閉を調べています。
withブロック内ではf.closed
はFalse(つまりファイルオブジェクトはメモリにのったまま)ですが、ブロックを出るとf.closed
はTrueでファイルは閉じられています。
withは、enterとexitを使って次のように書き換えることができます。
f = open('test.txt', 'r')
obj = f.__enter__()
try:
print("1:", f.readlines())
print("2:", f.closed)
finally:
print("3:", f.closed)
obj.__exit__()
print("4:", f.closed)
1: ['text']
2: False
3: False
4: True
2: False
3: False
4: True
まずobj.enter()でオブジェクトをコンテキストでの管理を開始します。
obj.exit()によってオブジェクトの管理が終了し、リソースから削除されます(f.close()と同じことです)。
コンテキストはいつ使われるか?
- ファイルの開閉する時
- 小数点精度を状況によって変更したいような時
状況に応じて(withブロック内でのみ)特殊な操作をしたい時に便利ですね。
コンテキストマネージャーwithが使えるクラスの作成方法
クラスから作成したインスタンスがwithに対応するためには、
そのクラスがenterとexitメソッドを持つようにする必要があります。
withブロックのスコープはforループや関数とは異なる
withブロックのスコープはforループや関数とは異なり、その変数はグローバルスコープに属している。
__exit__の振る舞い
try文のfinallyと同じで、withブロックで例外が発生しても、exitは実行されます。
コメント