withの概要
| リソースの準備と自動解放 Python予約語 | ||
|
with 概要 わかりやすく説明 |
||
|
withの考え方をイメージで理解

withを使ったファイルの読み込み操作
外部のテキストファイルを開いて中身のデータを読み出す、Pythonの実務で最も頻出する with の基本形です。
# with を使ったファイルの安全な読み込み
with open("example.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content) # ファイルの内容を表示
# このインデントブロックを抜けた瞬間に、file.close() が自動的に実行されています
as 変数名と記述することで、開いたファイルオブジェクトにブロック内でアクセスするための名前(リモコン)を与えることができます。
withを使ったファイルの書き込み操作
ファイルに新しくテキストを書き込む(上書き保存する)際も、with を用いることでバッファ(メモリに一時保存されたデータ)の強制書き出しとクローズが安全に保証されます。
# with を使ったファイルの書き込み
with open("output.txt", "w", encoding="utf-8") as file:
file.write("こんにちは、Python!")
# 記述ミス等でエラーが起きても、書き込み途中のファイルはシステムによって保護され、正しく閉じられます
withを使った複数のリソース管理
「あるファイルからデータを読み込み、別のファイルへ書き出す」といった2つのリソースが絡む処理も、1つの with 文の後ろに並べるだけでスッキリ記述できます。
# 2つのファイルを同時に開いて安全に制御
with open("input.txt", "r", encoding="utf-8") as infile, open("output.txt", "w", encoding="utf-8") as outfile:
for line in infile:
outfile.write(line.upper()) # 読み込んだ行を大文字にして書き込み
# ブロックを抜ければ、infile と outfile の両方が同時に自動クローズされます
withを使ったデータベース接続
データベースへの書き込み操作(トランザクション)において、途中でエラーが起きたら巻き戻し(ロールバック)、成功したら確定(コミット)して接続を閉じる、という一連の流れを自動化する例です。
import sqlite3
# データベースに接続
with sqlite3.connect("example.db") as conn:
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
# 正常にブロックを抜ければ、自動的にコミット(保存)されて接続が安全に切断されます
withを使ったスレッドロック処理
マルチスレッド(並行処理)プログラミングにおいて、複数の処理が同時に同じデータを書き換えてシステムが破壊されないよう、特定の部屋に「鍵をかけ、用が済んだら自動で鍵を返す」制御を with で一元管理する例です。
import threading
lock = threading.Lock()
def critical_section():
# 部屋に入る時に自動ロック(排他制御)
with lock:
print("現在、他のスレッドが侵入できない安全なクリティカルセクションを処理中です")
# ブロックを抜けた瞬間に、自動でアンロック(解錠)され他のスレッドに権利が譲られます
try-finally構文を使った場合との比較
with を使わない旧来の手法(try-finally)との比較です。with がどれほど美しく安全なコードを実現しているかが一目で分かります。
# 【非推奨:try-finally による泥臭い管理】
file = open("example.txt", "r", encoding="utf-8")
try:
content = file.read()
print(content)
finally:
# 途中でどんな深刻なエラーが起きても、ここだけは絶対実行してファイルを閉じる
file.close()
# 💡「with open(...) as file:」を使えば、上記5行の面倒な記述をわずか2行で、同等以上の安全性で実装できます
withの注意点
- どんなオブジェクトにでも with が使えるわけではない:
withを適用できるのは、内部に__enter__()(開始時の処理)と__exit__()(終了時のクリーンアップ処理)という特別なメソッドがあらかじめ仕込まれている「コンテキストマネージャ」と呼ばれるオブジェクトだけです。普通の数値や自作した単純なクラスに対してwithを使うとAttributeErrorになります。 - with ブロック内で発生した例外は、自動で消滅(キャッチ)するわけではない:
withはリソースを「確実に閉じる」ためのものであり、エラーそのものを無かったことにしてくれる魔法ではありません。ブロック内でエラーが起きれば、ファイルは正常に閉じられますが、プログラム自体はその場で例外エラーを出してストップします。エラーを検知して独自のリカバリー処理を行いたい場合は、通常通りwithの外側をさらにtry-except文で囲む必要があります。
withのよくある質問
- Q: 自分が作ったオリジナルのクラスを `with` に対応させることはできますか?
- A: 非常に簡単に実装できます。クラスの中に
__enter__と__exit__の2つのメソッドを定義するだけで、即座にコンテキストマネージャとしてwithに適合させることができます。# 自作クラスを with に対応させる例 class CustomResource: def __enter__(self): print("【準備】リソースを確保しました") return self # as 変数名 に渡されるオブジェクト def __exit__(self, exc_type, exc_val, exc_tb): print("【後片付け】リソースを自動解放しました") # ここで True を返すと、ブロック内のエラーをここで握り潰すことも可能です # テスト実行 with CustomResource() as res: print("ブロック内部のメイン処理を実行中...")実務では、自作の通信クライアントやAPIのモック(テスト用ダミー)を作成する際などに重宝するテクニックです。
- Q: `with open(...)` の中で定義した変数(content など)は、with のブロックの外側からはアクセスできなくなりますか?
- A: いいえ、普通にアクセス(利用)可能です。 Pythonの仕様では、
ifやfor、withのインデントブロックは「新しい変数のスコープ(生存範囲)」を作らないため、ブロックの中で代入された変数は、withが終了してファイルが完全に閉じられた後でも、その下層のコードから自由に呼び出すことができます(ただし、ファイルを開くこと自体に失敗した場合は変数が作られないためエラーになります)。
まとめ
with は、リソースの取得から破棄までのライフサイクルをシステムレベルで厳格に自動管理し、開発者を不注意によるメモリリークやファイルロックのバグから解放するための、極めてエレガントな予約語です。
- ファイル操作、DB接続、並行処理のロック制御など、クローズ処理が絶対不可欠なシーンにおける業界標準(ベストプラクティス)。
try-finallyの冗長なボイラープレート(定型コード)を駆逐し、インデントで視覚的にリソースの有効範囲を明示する。- 実務でのインフラ層の構築やファイル入出力において、
withを正しく使うことはバグのない堅牢なアプリケーション開発の最低条件。
Pythonic(Pythonらしい美しさ)を象徴するこの with 構文を徹底して使いこなし、何があってもリソースが安全に保護される、高品質なコード設計の基礎を身につけましょう。