Python の with 文で複数のリソースを扱う
複数のリソースを同時に扱いたい場合、with 文にはいくつかの書き方があります。状況に応じて使い分けましょう。
カンマ区切りで複数指定
最もシンプルな方法は、カンマで区切って複数のコンテキストマネージャを指定することです。
with open("input.txt", "r") as infile, open("output.txt", "w") as outfile:
for line in infile:
outfile.write(line.upper())この書き方では、すべてのリソースが同時に確保され、ブロック終了時にすべて解放されます。
括弧を使った複数行表記
Python 3.10 以降では、括弧を使って複数行に分けて書けます。
with (
open("input.txt", "r") as infile,
open("output.txt", "w") as outfile,
open("log.txt", "a") as logfile
):
for line in infile:
outfile.write(line.upper())
logfile.write(f"処理: {line}")リソースが多い場合に読みやすくなります。
バックスラッシュによる継続(古い方法)
Python 3.9 以前では、バックスラッシュで行を継続する方法が使われていました。
with open("input.txt", "r") as infile, \
open("output.txt", "w") as outfile:
for line in infile:
outfile.write(line.upper())この書き方は今でも動作しますが、括弧を使う方法の方が推奨されます。
ネストした with 文
with 文をネストすることもできます。
with open("input.txt", "r") as infile:
with open("output.txt", "w") as outfile:
for line in infile:
outfile.write(line.upper())ただし、インデントが深くなるため、カンマ区切りの方が一般的に好まれます。
リソースの解放順序
複数のリソースは、指定した順序と逆の順序で解放されます。
class Resource:
def __init__(self, name):
self.name = name
def __enter__(self):
print(f"{self.name}: 確保")
return self
def __exit__(self, *args):
print(f"{self.name}: 解放")
with Resource("A"), Resource("B"), Resource("C"):
print("処理中")
# 出力:
# A: 確保
# B: 確保
# C: 確保
# 処理中
# C: 解放
# B: 解放
# A: 解放これは「後入れ先出し」(LIFO)の順序で、スタック的な動作になります。
実用例:ファイルのコピー
複数ファイルを扱う典型的な例として、ファイルコピーがあります。
def copy_file(src, dst):
with open(src, "rb") as fsrc, open(dst, "wb") as fdst:
while chunk := fsrc.read(8192):
fdst.write(chunk)
copy_file("original.dat", "backup.dat")入力と出力を同時に開くことで、効率的にコピーできます。どちらかでエラーが発生しても、両方のファイルが確実に閉じられます。



