この記事のポイント

  • openとpathlibを活用したファイルI/O設計整理をレビュー視点で体系理解できる
  • リソース管理、パス操作、例外責任整理の技法を学べる
  • 実務でのファイル設計文化を体系化できる
  • PlantUMLでI/O責務依存構造を可視化整理できる

そもそもopenとpathlibとは

PythonのファイルI/Oは長年open()中心で利用されてきましたが、近年はpathlib高レベルAPIとして設計整理を支援します。

機能領域 代表API 主設計責務
ファイルオープン open() リソース制御責務
パス操作 pathlib.Path パス整形・存在確認責務
例外制御 try-except 異常系整理責務
open基本例

with open("data.txt", "r") as f:
    data = f.read()
pathlib基本例

from pathlib import Path

p = Path("data.txt")
data = p.read_text()
  • pathlibはI/Oとパス処理の責務分離を支援
  • openは細粒度のファイル操作制御に依然重要

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

ファイルI/O設計は「生存期間と例外責任が混在しやすい領域」です。
レビューアーは以下の整理視点を持つ必要があります。

レビューアー視点

  • with構文が適切に適用されているか
  • パス組立責務が文字列操作に埋没していないか
  • 例外発生時の開放責任が保証されているか
  • 事前存在確認 vs 例外捕捉方針が整理されているか
  • モジュール化されたI/O責務分離が整理されているか

開発者視点

  • 文字列連結でパスを組みがち
  • open()単独使用で開放漏洩しがち
  • try-exceptが粒度過剰 or 不足
  • pathlibを導入し切れずに混在

ファイルI/O崩壊の典型設計臭

崩壊しやすいパターン
  • open()を単独使用しclose忘れ
  • os.path.join()と文字列連結混在
  • 存在確認をifで冗長分岐
  • 例外設計が広域try-exceptで肥大
  • I/O責務が複数層に分散

崩壊例:開放漏洩型

close忘れ例

f = open("data.txt", "r")
data = f.read()
# close忘れ
@Reviewer
ファイルリソース開放責務が不備です。with構文を必ず適用してください。

問題点

  • リソースリーク発生
  • 例外発生時に開放保証消失

崩壊構造モデル:開放漏洩構造

UML Diagram

ファイルI/O設計整理の原則

以下の責務整理文化が健全性維持に有効です。

① with構文強制文化

  • openは必ずwith内で制御

② pathlib優先文化

  • パス操作はPath()で責務明示化

③ I/O責務分離文化

  • 読み込み・書き込み処理をAPI単位に整理

④ 例外経路設計文化

  • 例外捕捉は呼出境界で整理集中

⑤ 存在確認整理文化

  • if存在確認は極力省略 → 例外活用へ

改善例:責務整理版

pathlib整理版

from pathlib import Path

def read_file(file_path: Path) -> str:
    return file_path.read_text()

p = Path("data.txt")
data = read_file(p)
「with文化+pathlib文化+責務分離文化」

レビューアーは「文字列操作排除文化」を徹底確認すると設計臭抑止できます。

改善構造モデル:責務分離整理

UML Diagram

良くない実装例: ケース1(文字列連結型)

文字列連結例

file_path = "/data/" + filename + ".txt"
with open(file_path, "r") as f:
    data = f.read()
@Reviewer
パス組立に文字列連結を使用しています。pathlib活用で責務分離整理してください。

問題点

  • OS依存パス表現
  • 拡張性・保守性劣化

改善例:pathlib組立整理

pathlib組立版

from pathlib import Path

p = Path("/data") / f"{filename}.txt"
data = p.read_text()
  • OS非依存
  • パス構造明示化

良くない実装例: ケース2(冗長存在確認)

存在確認例

if os.path.exists(file_path):
    with open(file_path, "r") as f:
        data = f.read()
else:
    raise FileNotFoundError()
@Reviewer
存在確認は不要です。open自体がFileNotFoundErrorを発生させます。例外活用に整理してください。

問題点

  • 二重確認冗長
  • レースコンディション温床

改善例:例外活用整理

例外活用版

try:
    data = Path(file_path).read_text()
except FileNotFoundError:
    handle_missing_file()
  • OS依存消失
  • 例外経路に整理集中

良くない実装例: ケース3(広域try-except)

try全域例

try:
    p = Path(file_path)
    with p.open("r") as f:
        data = f.read()
    process(data)
except Exception as e:
    logger.error(e)
@Reviewer
try領域が広域化し障害特定が困難です。責務分離して捕捉粒度を整理してください。

問題点

  • 捕捉粒度不明確
  • 例外原因追跡困難

改善例:例外粒度整理版

例外粒度整理

p = Path(file_path)
try:
    data = p.read_text()
except FileNotFoundError:
    handle_missing_file()
process(data)
  • 各責務単位で例外経路整理

観点チェックリスト

まとめ

ファイルI/O設計は「低層ライフサイクル設計の縮図」です。
レビューアーは「with文化・pathlib文化・例外責任文化」を育成指導することで、
障害耐性と保守性の高いファイル設計を安定化できます。