Python:例外処理(try/except)の解説
音声
目次
例外処理の基本と今回できること
今回できるようになることは、ユーザー入力やファイル操作で起きる代表的なエラーを捕まえて、安全に処理を続けられるようになることです。
例外(エクセプション)は、プログラム実行時に発生する問題のことです。Pythonではtryブロックに正常処理を置き、exceptブロックで特定の例外を補足します。
exceptは複数書けるため、例外の種類ごとに処理を分岐できます。また、elseブロックで例外が発生しなかった場合の処理を分けられます。
finallyブロックでは、後片付け処理(クローズなど)を例外の有無にかかわらず常に実行できます。まずは小さな例で流れをつかめます。
最小コードと実行方法
最小コードは次のとおりです。
# try_example.py
try:
a = input("分子を入力してください:")
b = input("分母を入力してください:")
num = int(a)
den = int(b)
result = num / den
except ValueError as e:
print("数値ではありません:", e)
except ZeroDivisionError:
print("0で割れません")
except Exception as e:
print("予期せぬエラー:", type(e).__name__)
else:
print("結果:", result)
finally:
print("処理終了")
このコードは、入力を数値に変換して割り算を試みます。入力が不正な場合や0除算、その他の例外に応じて該当するexceptが動作し、メッセージを出力します。例外が発生しない場合はelseで結果を出力し、最後にfinallyで終了メッセージを出力します。
実行方法は次のとおりです。
- ターミナルで保存したファイルを実行する場合は、
python try_example.pyと入力して実行します。 - VSCodeではファイルを開き、右上の「Run」またはF5で実行します。
python try_example.py
出力例は次のとおりです。
- 入力が10と2の場合は、「結果: 5.0」の後に「処理終了」が出力されます。
- 入力がabcの場合は、「数値ではありません: invalid literal for int() with base 10: 'abc'」の後に「処理終了」が出力されます。
使い分けの基準とデバッグの見方
特定の復旧が可能なエラーは、その例外名(ValueError、FileNotFoundError など)を個別に捕まえて処理するのが基準です。
ログを残すだけで先に進めない場合は、Exception で捕まえた後に再送出(raise)する選択肢もあります。
デバッグでは、まずは print() で変数の型や途中値を確認すると状況を切り分けやすいです。より本格的には logging モジュールでレベル(DEBUG/INFO/WARNING/ERROR)を設定してログを出す方法が便利です。
import logging
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s:%(message)s")
logging.debug("num=%s, den=%s", num, den)
確認方法としては、int() の後や除算の直前に print(type(num), num) のように出力して、型と値を目視すると良いです。ユニットテストで異常系を用意して自動確認する方法もあります。
よくあるミスは、原因と直し方をセットで押さえるのがポイントです。
- ミスとして、except Exception: や bare except で全てを捕まえてしまい、バグの原因が隠れる場合があります。直し方として、捕まえる例外を特定するか、ログを残した上で raise して再送出します。
- ミスとして、input のまま計算して ValueError になる場合があります。直し方として、int() の前後で print や type を入れて確認するか、ユーザー入力のバリデーションを追加します。
1段ステップアップ:関数化とファイル対応
関数化すると再利用とテストがしやすくなります。ファイル対応では open で発生し得る例外も扱います。例として、ファイルから数字を読み取り合計する関数です。
def sum_integers_from_file(path):
try:
with open(path, "r", encoding="utf-8") as f:
total = 0
for line in f:
total += int(line.strip())
except FileNotFoundError:
print("ファイルが見つかりません:", path)
return None
except ValueError as e:
print("数値変換エラー:", e)
return None
else:
return total
ファイルが無ければ FileNotFoundError を報告して None を返します。行の値が数値でなければ ValueError を捕まえて報告します。長い処理では try を狭めて影響範囲を限定するのがポイントです。
注意(ここだけ)
- 例外を安易に握りつぶして何もせずに
のようにすると原因の追跡が難しくなるため、ログ出力やエラーメッセージを残すか、処理できない例外は再送出するのがポイントです。except: pass
要約
- try/except/else/finally を使うと、正常系・異常系・後片付けを分けて書けます。
- 例外は種類ごとに捕まえ、必要であれば再送出する基準を決めておくのがポイントです。
- デバッグはまず print を使い、規模が大きい場合は logging を使って可観測性を高めるとよいです。
- 関数化やファイル操作では、例外の対象範囲を狭めて影響を限定すると有効です。
- 例外をそのまま無視せず、ログやメッセージで原因を残すことが重要です。