🥤
[Python] 条件付きwith・複数リソースの一括解放
筆者の環境・参考文献
- Python 3.10
- 本記事の内容は3.7以降なら使えるはず (nullcontext)
一言でいえば、contextlibを勉強しなければと思いました。
内容は以下をただ書き直しているだけになりますが:
- https://stackoverflow.com/questions/27803059/conditional-with-statement-in-python
- https://docs.python.org/3/library/contextlib.html#replacing-any-use-of-try-finally-and-flag-variables
課題1: 条件付きwith
特定の条件でだけwithを書きたい場面がたまにあります。withにNoneは入れられません。どうすればよいか。
def foo(flag: bool) -> None:
file = None
if flag:
file = open("out.txt", "w")
...
if file:
file.write("Hello")
...
if file:
file.close()
contextlib.nullcontext を使えば、withに入れ込むことができます。nullcontextが選ばれた場合、以下のコードでのfile
はNone
になります。
from contextlib import nullcontext
def foo(flag: bool) -> None:
with open("out.txt", "w") if flag else nullcontext() as file:
...
if file:
file.write("Hello")
これは以下のコードと同じです。__enter__
がNoneを返すので、fileがNoneになるわけです。
class my_null_context:
def __enter__(self):
return None
def __exit__(self, exc_type, exc_value, traceback):
return False
def foo(flag: bool) -> None:
with open("out.txt", "w") if flag else my_null_context() as file:
...
課題2: 複数リソースの一括解放
たくさんの要解放リソースを一気にインスタンス化したい場面がたまにあります。どうすればよいか。
file_names = ["foo.txt", "bar.txt", "baz.txt"]
handles = []
try:
handles = [open(f, "w") for f in file_names]
for h in handles:
h.write("Goodbye")
finally:
for h in handles:
h.close()
contextlib.ExitStackが便利です。公式ドキュメントで一番に載っている例ですが。
from contextlib import ExitStack
file_names = ["foo.txt", "bar.txt", "baz.txt"]
with ExitStack() as stack:
handles = [stack.enter_context(open(f, "w")) for f in file_names]
for h in handles:
h.write("Goodbye") # enter_contextで包んでいますが、意識せず同様に使えます。
Discussion