この記事のポイント

  • with構文のリソース解放責務設計をレビューできる
  • 実務で頻発する解放漏れ・責務崩壊パターンを見抜ける
  • finally・tryとの使い分けを含めた設計視点を身につける

そもそもwith構文とは

Pythonのwith構文はコンテキストマネージャを利用し、リソース解放や後処理を自動化する仕組みです。

with open("file.txt", "r") as f:
    data = f.read()
  • __enter__()でリソース確保
  • __exit__()で解放処理

ファイル操作・ロック管理・ネットワーク接続など様々な場面で使われています。

なぜこれをレビューするのか

現場で頻発する失敗は以下の通りです。

  • with構文を使わず明示解放を強要
  • 複数リソースの開放順序崩壊
  • コンテキストマネージャ責務の肥大化
  • 例外時に解放漏れが発生

レビューアーは 「解放責務が誰にあるのか」 を常に読み解きます。

レビューアー視点

  • with構文が適切に利用されているか
  • 複数リソース管理の順序整理
  • コンテキスト化すべき独自リソースが裸で使われていないか
  • finally濫用・冗長tryがないか
  • 開放忘れの可能性が排除されているか

開発者視点

  • 可能な限りwith化で責務移譲する
  • 例外発生有無に関係なく確実に開放される構造にする
  • 複数リソースはネストではなく分離管理を検討
  • 独自リソースはcontextlibを活用し自前マネージャ化
  • finallyは最低限に限定

良い実装例

なぜこの実装が良いのか

  • with構文で自動解放保証
  • 複数リソースをネスト順序で安全管理
  • 例外発生有無に関わらず必ずリソース解放
  • finally依存ゼロで責務明確
# api_request_archiver.py

import gzip
import shutil

def archive_request_log(source_file, archive_file):
    with open(source_file, "rb") as src, gzip.open(archive_file, "wb") as dst:
        shutil.copyfileobj(src, dst)
補足

リソース確保〜解放までの責務が明確にwithブロックで表現されています。開発者がうっかり解放忘れを起こせない安全設計です。

レビュー観点

  • with構文活用有無(原則使い得)
  • ネスト順序の妥当性
  • 独自リソースはcontextlib活用しているか
  • 明示解放処理の残存有無
  • finally濫用箇所の排除

良くない実装例: ケース1(明示解放依存)

# bad_manual_close.py

import gzip
import shutil

def archive_request_log(source_file, archive_file):
    src = open(source_file, "rb")
    dst = gzip.open(archive_file, "wb")
    try:
        shutil.copyfileobj(src, dst)
    finally:
        src.close()
        dst.close()
@Reviewer
明示解放依存は例外網羅性の欠落や保守性低下を招きます。with構文を活用してください。

問題点

  • finally依存
  • 解放責務の漏洩
  • 記述負荷上昇

改善例

# good_with_context.py

import gzip
import shutil

def archive_request_log(source_file, archive_file):
    with open(source_file, "rb") as src, gzip.open(archive_file, "wb") as dst:
        shutil.copyfileobj(src, dst)

リソース解放責務は常に言語機構へ任せる方が安全です。
レビュー時は「自力close」を見つけ次第指摘対象にします。

良くない実装例: ケース2(独自リソースのcontext未対応)

# bad_custom_resource.py

class CustomConnection:
    def connect(self):
        print("接続確立")

    def disconnect(self):
        print("接続終了")

def use_custom_resource():
    conn = CustomConnection()
    conn.connect()
    try:
        # 実処理
        pass
    finally:
        conn.disconnect()
@Reviewer
独自リソースもcontextlib活用でコンテキスト化してください。明示close排除が原則です。

問題点

  • contextlib未活用
  • finally乱用
  • API利用側で開放責務発生

改善例

# good_custom_context_manager.py

from contextlib import contextmanager

class CustomConnection:
    def connect(self):
        print("接続確立")

    def disconnect(self):
        print("接続終了")

@contextmanager
def managed_connection():
    conn = CustomConnection()
    conn.connect()
    try:
        yield conn
    finally:
        conn.disconnect()

def use_custom_resource():
    with managed_connection() as conn:
        # 実処理
        pass

独自リソースでも可能な限りcontextlibでコンテキスト化し、利用者側はwithだけを意識するAPI構造が理想形です。

良くない実装例: ケース3(ネスト崩壊・開放順序設計漏れ)

# bad_nested_context.py

import gzip
import shutil

def archive_request_log(source_file, archive_file):
    src = open(source_file, "rb")
    try:
        dst = gzip.open(archive_file, "wb")
        try:
            shutil.copyfileobj(src, dst)
        finally:
            dst.close()
    finally:
        src.close()
@Reviewer
ネスト構造が手動管理となっており保守性が低下しています。with構文で自然に順序を表現してください。

問題点

  • ネストがtry依存で複雑化
  • 開放順序をコード維持者が常に考慮必要
  • 構文上の事故リスク上昇

改善例

# good_with_nested.py

import gzip
import shutil

def archive_request_log(source_file, archive_file):
    with open(source_file, "rb") as src, gzip.open(archive_file, "wb") as dst:
        shutil.copyfileobj(src, dst)

ネスト構造はwith構文が最も自然に安全順序を提供します。
レビューで手動ネストは即時指摘対象です。

観点チェックリスト

まとめ

リソース解放責務は設計全体の健全性を如実に表す鏡です。
レビューアーはwith構文活用を最優先観点とし、
「明示解放箇所=レビュー優先指摘箇所」として読んでいくと実務で非常に高精度に指摘できます。

責務は持たせない、任せる、機構に移譲する。
with構文レビューは現場設計者育成における極めて重要な教材となります。