Pythonのtry文をあいまいに理解したまま業務スクリプトや自動化を回すと、エラーが出ない代わりに「静かなデータ欠損」や「気づかないレポート不整合」が積み上がります。多くの解説や自動生成コードは、Python try exceptの構文やサンプルで終わり、どこまでをtryで囲み、何を握りつぶしてはいけないかという設計には踏み込みません。そこで本記事では、Pythonのtry文、try except/else/finallyの基本構文から、Exception as eでのエラーメッセージ取得、try finallyとwith、try returnの挙動までを一気に整理しつつ、ifとの違いをEAFPとLBYLの観点で解きほぐします。さらに、ファイル操作やAPI通信、ユーザー入力、forやwhile内のtry except、passで「何もしないexcept」が許される条件、bareなexceptやtry範囲の失敗例など、現場で本当に問題になるポイントを具体的に示します。「落とさないコード」ではなく「問題が見えるコード」に書き換えるための実務ベストプラクティスを、この記事1本で取り切ってください。
Pythonのtry文は例外を想定内の失敗として捉え、その発生パターンに応じてexcept/else/finallyで適切に処理を分岐させ、ログ出力やリソース解放を確実に実行するための仕組みです。
- Pythonの例外処理は単に例外を握りつぶすのではなく、想定内の失敗ごとに適切なexceptブロックを設計し、ログに残すことが運用品質を決定します。
- try/except/else/finallyの4つのブロックの役割を正確に理解することで、ファイル操作やAPI通信などの実務処理で堅牢で追跡可能なコードが書けます。
- bareなexceptやException全体キャッチではなく、発生しうる例外クラスを明示し、エラーメッセージを記録する設計パターンを心がけることが現場での事故防止につながります。
- Pythonのtry文とは|例外とエラー処理の基本を3分で把握する
- Pythonのtry文構文を一気に整理|tryとexceptとelseとfinallyの役割
- Pythonの例外クラスとexceptの書き方|Exception as eでエラーの中身を記録する
- ifとtry文の違いを理解する|Python例外処理と条件分岐の使い分け
- ファイル操作・API通信・入力チェック|try文が活躍する3つの実務シーン
- ループとreturnの中のtry文|forやwhileでの例外処理の設計
- with文とfinallyでリソース管理|自動で後片付けを完結させる
- 危ないtry文の落とし穴|「動いている風」コードが事故る瞬間
- 運用に強いPython例外処理|「落とさない」より「問題が見える」コード設計へ
- この記事を書いた理由
Pythonのtry文とは|例外とエラー処理の基本を3分で把握する
「月末バッチだけ落ちる」「API連携だけ時々止まる」──ログを開くと赤字だらけ、でも原因がつかめない。そんな消耗戦から抜け出す入口が、tryによる例外処理です。ここを腹落ちさせるかどうかで、スクリプトが「運任せの爆弾」か「安心して任せられる相棒」かが決まります。
例外とエラーの違いを「想定内の失敗」としてイメージする
エラーと聞くと「バグ」「致命的な失敗」を連想しがちですが、例外は少し違います。私の視点で言いますと、例外は「起きうる失敗を、あらかじめ名前を付けておく仕組み」です。
| 種類 | 例 | 開発者のスタンス |
|---|---|---|
| 単なるバグ | 変数名のタイプミス | そもそも起きないように直す |
| 例外(想定内の失敗) | ZeroDivisionError、FileNotFoundError | 起きうる前提で処理を設計する |
ZeroDivisionErrorは「0で割ったら失敗するかもしれない」という合図です。tryによる例外処理は、この合図をキャッチして「落とすか、リトライするか、ログだけ出して先へ進むか」を選べるようにする仕組みだと捉えると、本質が見えやすくなります。
Pythonのtryとexceptとelseとfinallyを一気に図解する
例外処理は4つのブロックの役割を押さえると、途端に整理されます。
-
try: 「ここで問題が起きるかもしれない」処理を書く場所
-
except: 例外が発生したときに走る「失敗時のルート」
-
else: 例外が発生しなかったときだけ走る「成功時専用ルート」
-
finally: 成功でも失敗でも必ず走る「後片付けルート」
頭の中では、次のようなフローでイメージすると扱いやすくなります。
- まずtryの中を実行する
- 途中で例外が発生したら、対応するexceptへジャンプ
- 例外が発生しなかった場合だけelseが実行される
- その後、成功でも失敗でもfinallyが必ず実行される
ファイル操作やAPI通信で「接続に失敗したらログだけ出す」「成功したときだけ結果を保存する」「最後は必ず接続を閉じる」といった流れを組むとき、この4つのブロックがきれいにハマります。
なぜPythonはtryがcatchではなくexceptなのか|他言語との発想ギャップ
JavaやC系の言語に慣れているエンジニアは、catchというキーワードを探して戸惑います。Pythonが採用しているのはexceptで、直訳すれば「例外的に」「〜以外は」です。この言葉の選び方に、設計思想の違いがにじみます。
-
catch: 「投げられたものを捕まえる」動作にフォーカス
-
except: 「通常フローから外れた場合」の扱いにフォーカス
Pythonでは「通常フロー」と「例外フロー」を対比させて読みやすくすることを重視しています。tryで通常フローを書き、exceptで例外フローを書き分けることで、「このコードは何を想定し、何を想定外として扱っているのか」が一目で追えるようになります。
ここを理解しているかどうかで、Exceptionクラスを乱用して全部キャッチしてしまう危険な書き方と、発生しうる例外を丁寧に選び分ける堅実な書き方の差がはっきり出ます。仕事で使うスクリプトほど、後者のスタンスが将来のトラブルを確実に減らしてくれます。
Pythonのtry文構文を一気に整理|tryとexceptとelseとfinallyの役割
エラーが出るたびに「とりあえずexceptで囲む」状態から抜け出すかどうかは、この構文ブロックをどこまで正確にイメージできるかで決まります。ここを押さえると、例外処理は一気に“怖くない武器”に変わります。
最小構成のtryがexcept文と、複数のexceptを書く鉄板パターン
まず、現場で実際によく使う最小構成は次の形です。
-
try:ブロック→「もしかしたら例外が発生するかもしれない処理」を書く
-
except 例外クラス:ブロック→起きてほしくない失敗が出た時の処理を書く
例えばゼロ除算の典型パターンです。
-
try: result = a / b -
except ZeroDivisionError:ユーザー向けに「0で割れません」とprint
ここで大事なのは、例外クラスを必ず指定するクセを付けることです。
複数の例外を分けたい時は、原因ごとにメッセージやログを変えられるように整理します。
| 目的 | 書き方の例 | メリット |
|---|---|---|
| 代表的な複数例外を個別処理 | except ZeroDivisionError: / except ValueError: |
ユーザーへの案内が具体的になる |
| 性質が近い例外をまとめて処理 | except (OSError, PermissionError): |
ファイルや権限エラーを一括で扱える |
| 最後の保険としてまとめて捕捉 | except Exception: |
ログ出力やアラート専用にできる |
特にファイル処理やユーザー入力では、「どの失敗をどんなメッセージで返すか」単位でexceptを分けると、後から読むエンジニアが原因を一瞬で特定しやすくなります。
運用でよく見るトラブルは、すべてを一つのexceptにまとめてしまい、ZeroDivisionErrorもファイルエラーも同じprintだけで終わってしまうケースです。これではログを見ても、どこで何が壊れたのか追えません。
elseとfinallyはいつ動く?「成功時だけ」と「必ず実行」の境界線
次に、挙動がイメージしづらいelseとfinallyです。ここを曖昧にしたまま本番コードを書くと、「なぜかログが二重に出る」「returnの場所を見失う」といった地味な事故を招きます。
| ブロック | 例外なし | 例外発生時 | 主な用途 |
|---|---|---|---|
| try | 実行される | 例外が出た行で中断 | メイン処理 |
| except | 実行されない | 条件に合うexceptだけ実行 | エラー時の処理 |
| else | 実行される | 実行されない | 正常終了後だけ行いたい処理 |
| finally | 必ず実行 | 必ず実行 | 後片付け・リソース解放 |
elseは「全部成功した時だけ動く場所」です。
例えば、ファイルの読み込み→パース→変数への格納までがすべて問題なく通った時だけ、「処理成功」をログに残したい、といった使い方が典型です。途中で例外が発生した場合は、elseには一切入らず、exceptで止まります。
一方でfinallyは「成功しても失敗しても必ず動く場所」です。
ファイルクローズやロック解除、APIセッションの終了など、「ここが動かないと次のバッチが巻き添えになる」処理は、tryの外ではなくfinallyに置くべきです。
私の視点で言いますと、finallyに書くべき処理をtryのすぐ後に素で書いてしまい、例外が起きた瞬間にその行がスキップされて障害が連鎖した、という事故は現場で何度も見ています。
すべての例外を捕まえる書き方と、bareなexceptが事故を生む理由
「とにかく落としたくないから全部捕まえたい」という場面も確かにあります。ここで候補になるのが次の2パターンです。
| 書き方 | 振る舞い | 問題点 |
|---|---|---|
except Exception as e: |
Exceptionを継承する例外をすべて捕まえる | システム終了系など一部は素通りするが、ほぼ“全部”拾う |
except:(bare except) |
BaseExceptionを含むすべてを捕まえる | KeyboardInterruptやSystemExitまで握りつぶす危険 |
except Exception as e:は、ログ出力やアラート通知の「最後の砦」としては有効です。ここでprint(type(e), e)のようにエラーメッセージとクラスを記録しておけば、「何の種類の例外がどこで発生しているのか」を後から追いやすくなります。
一方、bareなexcept:は、開発中のデバッグ用途を除き、運用コードではほぼ封印した方が安全です。
理由はシンプルで、ユーザーがCtrl+Cで止めようとしたKeyboardInterruptも、プロセス終了を示すSystemExitも全部キャッチしてしまい、passで握りつぶした瞬間に「止められないスクリプト」が出来上がるからです。
特に夜間バッチやレポート自動生成では、bareなexceptの中でpassだけ書かれたコードが、データ欠損を黙って増やし続ける温床になりがちです。
例外を全部キャッチしたい時は、必ずExceptionを明示し、「ログに残す」「アラートを飛ばす」「最低限の終了処理をしてから再raiseする」といった運用フローまでセットで設計すると、ただの“エラー隠し”から“情報を見える化するガード”に格上げできます。
Pythonの例外クラスとexceptの書き方|Exception as eでエラーの中身を記録する
「とりあえず例外を捕まえておきました」と書かれたスクリプトが、後から運用担当の財布を直撃するケースを何度も見てきました。鍵になるのは、例外クラスの理解とexceptの設計です。この章で、原因不明のエラー地獄から抜け出す土台を固めます。
PythonのExceptionとErrorの種類をざっくり押さえて迷子にならない
Pythonの例外階層は細かく見れば深いですが、現場で迷子にならないために押さえるべきポイントはシンプルです。
-
一番上にBaseException
-
通常の業務処理で扱うのはその下のException
-
Errorで終わるクラスは「何かがおかしい」状態を表す
代表例を整理するとイメージしやすくなります。
| 分類 | 代表的なクラス | よく出るシーン |
|---|---|---|
| 入力系 | ValueError, TypeError | ユーザー入力の変換ミス、型違い |
| 計算系 | ZeroDivisionError | 0で割り算する処理 |
| ファイル系 | FileNotFoundError, PermissionError | パス間違い、権限不足 |
| 通信系 | TimeoutError, OSError系 | APIやネットワーク接続 |
| アプリ共通 | RuntimeError, Exception | ライブラリ内部のエラー |
私の視点で言いますと、ここを「なんとなく」ではなく業務で使う場面とセットで覚えておくと、後の設計判断が一気に楽になります。
except Exception as eでエラーメッセージをログに残すリアルな書き方
例外を捕まえるだけでは意味がありません。運用で役立つ形に「可視化」して初めて価値が出ます。その入口がexcept Exception as eの書き方です。
典型的なパターンは3つセットで押さえてください。
-
例外クラス名を記録する
-
エラーメッセージを記録する
-
どの処理で起きたかを一緒に残す
たとえば、レポート生成バッチの中なら、次の情報を最低限ログに入れるべきです。
-
処理名や関数名(def名)
-
対象データのキー(ユーザーIDや日付など)
-
type(e).nameで取得した例外クラス名
-
str(e)で取得したエラーメッセージ
printで済ませるのではなく、業務ではloggingモジュールや外部のログ基盤に送る形にしておくと、後からの調査コストが一桁変わります。ここをケチってしまうと、「月末だけ失敗するAPI呼び出し」のような再現しづらい不具合が、永遠に捕まえられません。
何もしないexceptとpassはどこまでアリか|握りつぶしていいエラーとダメなエラー
一番危険なのが、except: やexcept Exception: の中でpassしてしまう書き方です。一見「システムが落ちない優しいコード」に見えますが、実態は「静かにデータを捨て続ける時限爆弾」になりがちです。
握りつぶしてよいかどうかは、次の観点で判断するとブレません。
| 扱い | 例 | ポイント |
|---|---|---|
| 条件付きで許容 | ユーザーが途中で入力をやめたKeyboardInterruptを捕まえて後片付けだけするケース | ログは残し、処理中断は明示する |
| 条件付きで許容 | 1件失敗しても統計には影響が薄い大量データ処理で、そのレコードだけスキップするケース | passではなく「スキップ件数」をカウントしておく |
| 完全にNG | APIエラーを握りつぶして古いキャッシュだけ返す処理 | 売上やレポートに直結する数字が静かに狂う |
| 完全にNG | データベース書き込み失敗を無視して処理続行 | 後から整合性チェック不能になる |
「どうしても一旦passしたい」場面では、少なくとも次の2点は守ってください。
-
必ずログか標準出力でエラーメッセージと対象データを記録する
-
コメントで「なぜ握りつぶしているか」「いつ見直すか」を明記する
tryの範囲を広げすぎて、どこで例外が発生したか分からなくなるのも典型的な落とし穴です。エラーを「消す」のではなく、「誰でも追える形で外に出す」。それが、業務運用に強い例外処理へアップグレードする第一歩になります。
ifとtry文の違いを理解する|Python例外処理と条件分岐の使い分け
「とりあえずifを足しておきました」で、月末バッチが静かにデータを落とし始める──現場でよく見るパターンです。条件分岐と例外処理の境界を押さえるだけで、こうした事故はかなり減らせます。
ifで事前チェックする時と、tryで実行してから捕まえる時の見極め方
実務では、次の軸で判断すると迷いにくくなります。
-
事前に確実に判定できるもの → if
-
実際にやってみないと分からないもの → try except
具体例を整理します。
| 状況 | 向いている書き方 | 理由 |
|---|---|---|
| 変数が空かどうかのチェック | if | メモリ上のデータで完結するため確実に判定できる |
| ユーザー入力が数値かどうか | try except ValueError | "10e"や空文字などパターンが無数にあり、全てをifで網羅しづらい |
| ファイルパスの形式チェック | if | 文字列としての形式はローカルで検査できる |
| ファイルを開く処理 | try except OSError | 存在・権限・ロック状態は、開いてみないと確定しない |
| APIリクエスト送信 | try except (TimeoutErrorなど) | ネットワークと相手サーバー事情は事前に読めない |
ifでチェックしても、他プロセスがファイルを削除する、VPNが落ちる、権限が途中で変わるといった外部要因は防げません。ここをifで完璧に守ろうとするほど、条件だらけの読みにくいコードになります。
Pythonの例外とifの関係をEAFPとLBYLで噛み砕く|速度より「事故リスク」で考える
Python文化ではよく次の2つが語られます。
-
LBYL (Look Before You Leap): 飛ぶ前に地面をよく見る → if主体
-
EAFP (Easier to Ask Forgiveness than Permission): とりあえず飛んで、ダメなら謝る → try主体
「どちらが速いか」という議論もありますが、業務スクリプトで本当に効いてくるのは速度より運用リスクです。
-
LBYLだけに頼ると
- ifでは検知できない外部要因で、想定外の例外がプロセスを落とす
- 条件分岐が増えすぎて、仕様変更時にどこを直せばよいか分からなくなる
-
EAFPをうまく使うと
- 実際に起きた例外に応じてログやアラートを飛ばせる
- 「どこで」「何が」失敗したかがログで明確になり、調査コストが下がる
私の視点で言いますと、小さな自動化でも「外部サービスに触れるところ」は原則EAFPで書いておくと、数ヶ月後のトラブル対応が桁違いに楽になります。仕様変更や一時的な障害が起こるのは、ほぼ外部との境界だからです。
初心者がやりがちなifとtryの二重ガードと、現場で使うシンプルルール
よく見かけるのが、次のような「二重ガード」です。
-
ifで状態を確認してから、同じ処理をtry exceptで再度囲う
-
さらにその外側を、広い範囲のtry except Exceptionでキャッチする
これが増えると、どの層が本当にエラーを握りつぶしているのか追えなくなります。現場では、次のシンプルルールに落とし込むと整理しやすくなります。
-
ルール1: メモリ上の単純な状態チェックはif、それ以外は基本try except
-
ルール2: ifとtryを同じ目的で二重に使わない
(どちらか一方に責任を持たせる)
-
ルール3: tryの範囲は「この1アクション」で失敗してよい最小単位に絞る
-
ルール4: 上位レイヤーのtry exceptは「ログを残して落とす」か「安全な代替フローに切り替える」かを明記する
-
ルール5: passだけのexceptは「本当に失ってよい情報」かをレビューで確認する
特にルール3が効いてきます。ファイルを開く部分、APIを叩く部分、ユーザー入力を変換する部分ごとに小さめのtryを置くことで、「どこが」「どんな例外で」落ちたかが一目で分かり、原因調査の時間を大きく削れます。
ifとtryの境界をこのレベルで言語化しておくと、担当交代があっても「なぜこの書き方なのか」が伝わりやすくなります。結果として、コードもビジネスも、予期せぬ落とし穴にはまりにくくなるはずです。
ファイル操作・API通信・入力チェック|try文が活躍する3つの実務シーン
「月末だけスクリプトが落ちる」「たまにデータが欠ける」ようなイヤな事故は、だいたいこの3つで起きます。ここを押さえると、業務自動化の安定度が一気に上がります。
ファイル操作のtry文|存在しないファイルと権限エラーを安全にさばく
ファイルは「ない・読めない・壊れている」の三拍子が典型パターンです。
私の視点で言いますと、例外ごとにメッセージを変えるだけで調査時間が半分以下になります。
| 状態 | 代表的な例外 | 考えるべき処理 |
|---|---|---|
| ファイルがない | FileNotFoundError | 初期ファイル作成・スキップ記録 |
| 権限がない | PermissionError | 管理者連絡・設定変更を促す |
| 中身が壊れてる | UnicodeDecodeErrorなど | 該当ファイルだけ隔離・ログ |
ポイントは次の3つです。
-
tryの範囲を「openからreadまで」のように最小限にする
-
exceptで例外クラスを個別指定し、printやログでパスと理由を必ず残す
-
finallyまたはwith文で、成功時も失敗時もファイルをきれいに閉じる
これを徹底すると、「どのファイルで何が起きたか」が一目で分かり、再現検証が楽になります。
APIや通信処理のtryがexcept|タイムアウトとHTTPエラーを切り分ける
APIは「コードは正しいのに外部要因で落ちる」典型です。
ネットワーク障害とHTTPエラーを同じexceptで握りつぶすと、運用チームが原因を特定できません。
押さえたい分け方は次の通りです。
-
接続できない・遅すぎる → TimeoutやConnectionError系
-
ステータスコード4xx → リクエスト内容の問題(トークン期限切れ、パラメータ不正)
-
ステータスコード5xx → 相手サーバ側の問題
運用を意識したパターンは、
-
タイムアウト時は再試行回数を制限してリトライ
-
4xxは「設定ミスなので担当者に通知」して即中断
-
5xxは「外部障害としてログ+アラートのみ」で自動リトライは慎重に
この切り分けをせず、except Exception as eだけにすると、「毎晩のバッチが静かに失敗し続け、レポートだけ欠けていた」という事態を招きます。
ユーザー入力とバリデーション|ValueErrorを味方につけたエラー処理フロー
入力チェックでありがちなのは、ifで文字種をがちがちに判定した結果、コードが読めなくなるパターンです。
ここはtryで変換を試みて、ダメならValueErrorを捕まえる方がシンプルになります。
-
intやfloatへの変換時は、tryでキャストを実行し、ValueErrorだけをexceptで捕捉
-
メッセージには「ユーザー向け文言」と「ログ向け詳細」を分けて用意
-
バリデーションエラーは処理を止めるのか、再入力させるのかを最初に決める
特に業務ツールでは、「入力が不正なら落とさない」よりも、どの入力が原因かを即わかるログが重要です。
名前やメールアドレスのようにビジネス影響が大きい項目ほど、ValueErrorを無視せず、必ずログと画面の両方で見えるようにしておくと、後からのトラブルシュートが格段に楽になります。
ループとreturnの中のtry文|forやwhileでの例外処理の設計
forとwhileの中でのtry文|一件だけ失敗しても処理を回し続けるコツ
バッチ処理やレポート集計で多いのが「1件エラーで全件ストップしてしまう」事故です。forの中での例外処理は、「1件の失敗」と「全体の失敗」を分けて考えることが肝になります。
典型パターンは次の2つです。
-
レコード単位の例外を握りつぶさずログだけ残し、ループは続ける
-
クリティカルな例外は即座にループを終わらせる
擬似コードで雰囲気をまとめると、
-
「続行したい例外」: ValueError、ユーザー入力の不正、個別ファイルの欠損
-
「即終了したい例外」: 認証エラー、DB接続エラー、APIの権限エラー
という切り分けが現場では多いです。
私の視点で言いますと、レポート自動化では「1ユーザー分のデータ取得失敗」はログだけ残し、夜間バッチ全体は止めない設計にしておくと、ビジネス側のストレスが一気に下がります。
tryがexceptとcontinueとbreakとreturn|どこで処理を止めるかの判断軸
forやwhileの中に例外処理とcontinue/break/returnを混在させると、一気に読みづらくなります。ポイントは「誰にとっての終了か」を表にして整理することです。
| 使うキーワード | 終了する範囲 | 典型シーン |
|---|---|---|
| continue | その反復だけスキップ | 1件だけ不正データで次へ進めたい |
| break | そのループ全体を終了 | 上限件数到達、重大エラー発生 |
| return | 関数全体を終了 | 呼び出し元へ即座に失敗を返したい |
判断軸は次の3つに絞ると迷いません。
-
この例外は「1件の問題」か「システム全体の問題」か
-
この場でリカバリーできるか、上位に委ねるべきか
-
止めることで、ビジネス側にどんな影響が出るか
たとえばSNS投稿バッチなら、1件のテキスト不備はcontinueで飛ばし、API認証エラーはbreakまたはreturnで即停止し、担当者にアラートを飛ばす、といった線引きが合理的です。
関数の中のtryとPythonのtryがfinallyがreturnの実行順をイメージでつかむ
関数の中で例外処理とreturnとfinallyを組み合わせた瞬間、多くのコードが「未来の自分も読めないスクリプト」に変わります。まず押さえたいのは実行順のイメージです。
-
tryブロックでreturnが実行されても、finallyブロックは必ず実行される
-
finallyの中で別のreturnや例外を発生させると、元の結果や例外は上書きされる
この2行動だけで、かなりのバグを避けられます。設計のコツは次の通りです。
-
finallyには副作用だけを書く(ファイルクローズ、ロック解放など)
-
値を返すロジックはtryかelseに集約し、finallyでreturnしない
-
例外を握りつぶさず、必要ならログを出してからraiseで再送出する
特に夜間バッチでは、finallyで静かに例外を上書きすると、ログにも残らずデータだけ欠損する「サイレントエラー」が起きがちです。
ループと関数内の例外処理は、どこで止めて誰に知らせるかを先に決め、その約束に合わせてtry、except、continue、break、return、finallyを配置すると、あとから読んでも怖くないコードになります。
with文とfinallyでリソース管理|自動で後片付けを完結させる
「処理は終わっているのに、ファイルが握りっぱなし」「API接続だけが大量に残ってサーバーが重い」
こうした“後片付け漏れ”は、現場では月末バッチや自動レポートで本当に多いトラブルです。ここで鍵になるのが、tryとfinally、そしてwith文の正しい役割分担です。
Pythonのtryがfinallyとwith文の役割分担|ファイルや通信を確実にクローズする
リソース管理を考えるときは、まず次の3つをはっきり分けて考えると事故が減ります。
| 役割 | 典型的な場所 | 主な対象 |
|---|---|---|
| 取得(開く) | with文の直後 / try内 | ファイル、ソケット、DB接続 |
| 利用(処理) | withブロック / try内 | 読み書き、送受信、クエリ実行 |
| 解放(閉じる) | withの自動クローズ / finally | close、commit / rollback |
基本方針はシンプルです。
-
ファイルやソケットのように「開いたら必ず閉じる」ものはwith文に任せる
-
with文で巻ききれない“後始末”はfinallyで保証する
ファイル処理を例にすると、次のような設計がリスクを抑えます。
-
ファイルを開く部分はwith
-
読み取り・パース処理はwithブロック
-
ログ出力や一時ファイル削除など「ファイル以外の後片付け」はfinally
私の視点で言いますと、トラブルが続く現場ほど「全部try finallyでやろう」として責務がぐちゃっと混ざっています。まずは「リソースのクローズはwithが第一候補」と覚えておくと設計が一段スッキリします。
例外が起きても必ず走らせたい処理はどこに書く?finallyの使いどころ
finallyが輝くのは、「処理結果が成功でも失敗でも、必ずやるべきこと」が決まっている場面です。典型的には次のようなものがあります。
-
ロックファイルの削除
-
一時ディレクトリの掃除
-
「このバッチは終わった」というフラグの更新
-
計測用タイマーの終了と実行時間ログの出力
ポイントは、正常終了と例外発生をまたぐ“境界の後処理”をまとめることです。
逆に、次のようなものをfinallyに押し込むと調査コストが急に跳ね上がります。
-
例外の詳細を握りつぶすログ上書き
-
成否に関わらず「成功しました」と見えるメッセージ出力
-
returnで関数の戻り値を書き換える処理
tryの中で問題が起きたのに、finallyが「成功ログ」を出してしまうと、運用担当はどこで失敗したか追えません。エンジニア目線では1行の違いですが、ビジネス側から見ると「レポートは届いているが中身の数字が抜けている」という致命的な事故につながります。
例外を発生させるraiseと、あえて再送出する設計が生きるシチュエーション
raiseは、例外処理の“非常ベル”です。
重要なのは、「どの階層でベルを鳴らし、どの階層で消火活動をするか」を決めることです。
現場でよく使うパターンは次の2つです。
| パターン | 目的 |
|---|---|
| 下位関数で詳細をログ→再送出 | 呼び出し元で処理中断を判断させる |
| 下位関数で例外を別クラスに包む | ドメイン固有の例外として意味を明確にする |
例えば、APIクライアント層ではネットワーク由来のエラーを細かく判別し、ログに詳細を残します。そのうえで、業務ロジック層には「外部サービス障害」という抽象度にまとめて再送出する、という設計が有効です。
このとき大事なのが、「この階層で握りつぶすと、ビジネス的に誰が困るか」を基準にすることです。
-
ユーザー入力エラーなら、その場でメッセージを出して握りつぶしてよい
-
決済や重要な集計処理なら、あえてraiseで止めて、人間の確認を必須にする
raiseを安易に消してしまうと、「とりあえず動いている風」なのに、あとで売上集計や広告レポートの数字が合わない、といった静かな破綻が起きます。
逆に、止めるべきところでしっかり止める設計をしておけば、夜間バッチが途中で落ちても、原因が明確で復旧も早くなります。
tryとfinally、with文、そしてraiseの役割をきちんと分けることが、単なるエラー処理ではなく「問題が見えるシステム運用」への最短ルートになります。
危ないtry文の落とし穴|「動いている風」コードが事故る瞬間
「エラー出てたけど、try exceptで握りつぶしておきました」
この一言が、数カ月後にレポートの数字ズレやSNS停止につながる瞬間を、エンジニアは何度も見ています。動いている“ように見える”コードほど危険です。
なんでもかんでもひとまとめにしたtry文が、原因調査を地獄に変える理由
次のような書き方は、現場では調査コスト爆増パターンです。
-
1つのtryブロックの中に
ファイル読み込み、API通信、データ整形、DB書き込みを全部入れる
-
except Exceptionで一括キャッチし、printだけ出して処理継続
-
どの行でどの例外クラスが発生したか分からない構造にする
こうなると、障害が起きたときにログから読み取れるのは「どこかでエラーが発生しました」だけです。
業務スクリプトでは、どの処理ステップで失敗したかを切り分けられるかどうかが、復旧時間を左右します。
そこで意識したいのが、tryの範囲を細かく刻む設計です。比較すると違いがはっきりします。
| 観点 | 悪い例: 巨大なtry | 良い例: 細かく分割 |
|---|---|---|
| 例外の場所 | 不明瞭 | 行レベルで特定しやすい |
| ログの粒度 | 「失敗しました」だけ | 「ファイル読込で失敗」まで出せる |
| 改修のしやすさ | 少し触ると全体に影響 | ブロック単位で安全に変更 |
| レビューのしやすさ | 追うだけで疲れる | 「1ブロック1責務」で読みやすい |
「tryは処理のかたまりごとに、理由を説明できる単位で切る」ことを基準にすると、運用が一気にラクになります。
tryがexceptがpass文化で起きる「静かなデータ欠損」と「気づかないエラー」
一番怖いのは、動かないコードではなく静かに間違った結果を出し続けるコードです。
特に危険なのが、次のパターンです。
-
except Exception: pass
-
except: pass
-
exceptでprintだけしてログも残さない
ここから生まれる典型的なトラブルは、次の2つです。
-
データ欠損
- 一部のレコードだけ保存に失敗しているのに、全体としては処理が終了
- 売上集計や広告レポートで「じわじわズレる」症状として現れる
-
サイレントエラー
- SNS投稿の一部が失敗しているのに誰も気づかない
- エラーメッセージも例外クラスもログに残っておらず、再現も困難
本当に握りつぶしてよい例外は、ユーザー体験を損なわず、ビジネス指標にも影響せず、発生しても統計的に無視できるレベルのものに限られます。
それ以外は少なくとも次を残すべきです。
-
例外クラス(ExceptionやZeroDivisionErrorなど)
-
エラーメッセージ(Exception message)
-
どの入力データで起きたか
-
実行時刻と処理ステップ名
passを使う場合は、「なぜ無視してよいのか」をコメントに残す癖をつけると、担当交代後の事故を強く防げます。
例外処理の設計ミスがSNS運用やレポート自動化に与えるビジネスダメージ
SNSや広告レポートの自動化スクリプトは、外部サービスの気まぐれに常にさらされています。
-
APIの仕様変更やレスポンス形式の変更
-
一時的なタイムアウトやアクセス制限
-
認証トークンやパスワードの期限切れ
-
ユーザー権限の変更で特定データだけ取得不可
ここで例外処理を誤ると、技術的な問題がビジネスの痛みに変換されます。
-
広告レポートのインプレッションが一部日付だけゼロ
→ exceptで握りつぶしたせいで、気づくのは月次報告の直前
-
自動投稿スクリプトが特定アカウントだけ失敗
→ 認証エラーをprintだけして放置し、ブランドアカウントだけ更新が止まる
-
分析用のデータ収集が半分止まっているのにアラートなし
→ 担当者が転職してから、誰もログを見ていなかったことが判明
私の視点で言いますと、運用に強い例外処理は「落とさないコード」ではなく「問題が起きた瞬間に誰が気づけるかを決めたコード」です。
ログ出力、エラーメッセージの扱い、raiseで再送出するかどうかを含めて、次のように考えるとブレません。
-
この例外は、ユーザーに知らせるべきか、運用担当だけでよいか
-
失敗したら即座に止めるべき処理か、続行してもよい処理か
-
一時的な例外(タイムアウトなど)か、設計ミス・バグ由来か
tryとexceptは文法ではなく運用ルールをコード化する道具です。
「とりあえず握りつぶす」から一歩進み、ビジネスと運用の目線でどこまで見せるかを決めていくと、同じコードでも事故の起きやすさがまったく変わります。
運用に強いPython例外処理|「落とさない」より「問題が見える」コード設計へ
スクリプトが「なんとなく落ちない」のは安全ではなく、むしろ一番こわい状態です。ログに何も残らないままデータだけ欠けていくと、月末レポートやSNS自動投稿の数字がおかしくなっても、誰も理由を説明できません。ここからは、運用に耐える例外処理をどう設計するかを整理します。
エラーを隠さず「誰が見るか」まで決める|ログとアラート設計の勘所
現場で事故になるかどうかは、「例外をキャッチしたか」ではなく「キャッチした後どう流したか」で決まります。
まず押さえたいのは、ログの粒度と担当者を最初に決めることです。
| レベル | 典型的な例外例 | 誰がいつ見るか |
|---|---|---|
| 致命的 | 認証エラー、DB接続失敗 | エンジニアが即時アラートで確認 |
| 警告 | 一部レコードだけValueError | 翌日の運用担当がログを確認 |
| 情報 | 正常終了ログ、件数サマリ | レポート担当が必要に応じて確認 |
ポイントは次の3つです。
-
エラーメッセージを必ず残す
exceptでExceptionを受けたら、メッセージとスタックトレースをログ出力し、最低でも日時と処理対象データを紐づけます。
-
アラートは「人が動く単位」に絞る
すべての例外でメールを飛ばすと、数日で誰も見なくなります。ビジネスが止まるレベルだけを即時通知にし、それ以外は日次レポートにまとめます。
-
ログの保管場所を決めて共有する
ログファイルのパスや閲覧方法をドキュメント化し、「どのエラーを誰が何日以内に見るか」を合意しておくことが運用の土台になります。
小さなスクリプトでも守りたい例外処理ルール|チーム開発への布石にする
社内のちょっとした自動化スクリプトほど、担当交代のたびに「黒魔術コード」になりがちです。小さなスクリプトでも、少なくとも次のルールだけは押さえておきたいところです。
-
exceptでpassだけを書かない
せめてログ出力、件数カウント、対象IDの記録のどれかは行います。
-
tryの範囲を最小限に絞る
ひとつのブロックにAPI呼び出しからファイル保存まで詰め込むと、どこで落ちたのか特定に時間がかかります。外部要因ごとに分ける発想が重要です。
-
意図をコメントに残す
「ここはAPI側の制限でたまに失敗するが、再試行で吸収する」といったビジネス背景を残しておくと、後任が例外処理を誤って削りにくくなります。
この3つを守るだけで、「個人スクリプト」がそのままチーム開発の資産に昇格します。
Web運用現場で磨かれた例外処理の考え方から、次に深掘りしたい学びポイント
WebやSNS運用の現場では、外部サービスの仕様変更や認証まわりのトラブルが避けられません。私の視点で言いますと、そうした環境で長く回る仕組みを作る人は、次の3点に必ず気を配っています。
-
ネットワーク、ファイル、ユーザー入力といった「壊れやすい境界」を意識して例外を設計すること
-
ifでの事前チェックに頼りすぎず、「実際にやってみてtryで受ける」EAFPスタイルを適切に使うこと
-
raiseで上位に例外を再送出し、「ここで止めるべきか、上で判断させるか」を設計レベルで決めること
この視点を持っておくと、単なる構文の知識が「ビジネスを守る例外処理」に変わります。次の一歩として、ループ内の例外とcontinue、with文とfinallyの関係、Exceptionクラスの階層を順番に押さえていくと、どんな現場でも通用するエラー処理の軸が手に入ります。
この記事を書いた理由
著者 – 伊藤 和則(nextlife事業部 責任者)
中小企業のWeb集客やSNS運用を支援していると、Pythonで組んだ自動レポートや投稿スクリプトが「止まらずに動いているのに、数字だけおかしい」「一部のデータだけ抜けている」と相談されることがよくあります。詳しく見ると、APIやファイル処理を大きなtryで囲み、bareなexceptやpassで握りつぶしているコードが原因になっているケースが少なくありません。
私自身、SNS管理ツールや自前スクリプトの不具合で、ログイン不可やインサイト欠損が起きたとき、適切な例外処理とログがなく、原因特定に時間を浪費した経験があります。逆に、tryとexcept、else、finallyの境界をきちんと設計し直したことで、エラー発生時も「どこで、何が起きたか」が数分で追える状態に変わりました。
この記事では、そうした現場のつまずきを整理し、ifとtryの使い分けや、ファイル・通信・ループ処理での設計の勘所を、業務でそのまま使える形に落とし込んでいます。Pythonの文法を覚えることが目的ではなく、ビジネスの数字と運用を守るために、どこまでをtryで囲み、何を絶対に隠さないかを共有したいと考えて執筆しました。


