Q1次のうち構文エラーの例として正しいものはどれですか?
try / except で例外をキャッチする
Python の例外処理 try / except / finally の基本を解説します。エラーを受け止めて処理を続ける書き方を一通り図解で押さえます。
この記事で扱う try / except は、実行中に発生したエラーを受け止めて、プログラムを止めずに処理を続けるための仕組みです。外部からのデータ取得、ユーザー入力の検証、ファイル操作など、失敗が前提の処理に使います。
構文エラーと実行時エラー
Python のエラーは大きく 2 種類あります。構文エラーはコードが Python の文法規則に違反しているときに発生し、プログラムが実行される前に検出されます。一方、実行時エラー(例外)は文法的には正しいものの、実行中に問題に遭遇したときに発生するエラーです。try / except でキャッチできるのは実行時エラーだけです。
構文エラーはコードを読み込んだ瞬間に検出されるため、プログラムは一度も実行されません。実行時エラーは行まで到達して初めて発生するため、try / except で受け止められます。
# 構文エラー:コロン抜け。行が実行される前にエラーになる
# if x > 0
# print("positive")
# 実行時エラー:文法は正しいが実行中に失敗する
x = 100
print(x / 0) # ZeroDivisionError: division by zero
print("ここには到達しない")
実行時エラーが出ると、その行以降はすべてスキップされます。次のコードを実行すると、最後の print() は呼ばれずに IndexError でプログラムが停止することを確認できます。
# 実行時エラーの確認:try を使わないとプログラムが止まる
numbers = [10, 20, 30]
print(numbers[10]) # IndexError: list index out of range
print("ここには到達しない")
# 出力:
# Traceback (most recent call last):
# File "...", line 3, in <module>
# IndexError: list index out of range
try / except の基本
try: ブロックに失敗しそうな処理を書き、except エラークラス: ブロックにその失敗を受けたときの処理を書きます。
try の中でエラーが起きた瞬間、残りの try 本体はスキップされ、対応する except に処理が飛びます。except の後ろにあるコードは、エラーが起きてもプログラムが止まらずに続きます。
try の本体を実行し、例外が起きなければ except はスキップされ、そのまま後続に進みます。例外が起きた場合は残りの try 本体をスキップして一致する except に飛び、処理後に後続へ進みます。
# try で囲むと、0 除算が起きても処理が止まらない
a = 100
try:
result = a / 0
print(result) # ここは実行されない
except ZeroDivisionError:
print("0 で割れません") # ここへ処理が飛ぶ
print("後続の処理") # try / except の後は必ず実行される
# 出力: 0 で割れません
# 後続の処理
as e で例外オブジェクトを受け取る
except エラークラス as e: と書くと、発生した例外の詳細が e に入ります。print(e) でエラーメッセージを、type(e) でエラーの種類を取り出せます。ログ出力やデバッグの手がかりとして記録しておくと、あとから原因を追いやすくなります。
user_input = "abc" # 本来は数値のはずが文字列が来た
try:
value = int(user_input)
except ValueError as e:
print("入力が数値ではありません")
print(f"詳細: {e}")
print(f"種類: {type(e).__name__}")
# 出力: 入力が数値ではありません
# 詳細: invalid literal for int() with base 10: 'abc'
# 種類: ValueError
エラーメッセージだけではどこで例外が起きたかが分からないため、デバッグでは import traceback と一緒に使うのが定番です。traceback.format_exc() で例外発生時の呼び出し経路(スタックトレース)を文字列として取り出せるので、ログ出力に残しておくと原因調査が一気に楽になります。
import traceback
try:
value = int("abc")
except ValueError as e:
print(f"詳細: {e}")
print(f"種類: {type(e).__name__}")
print("--- traceback ---")
print(traceback.format_exc())
# 出力:
# 詳細: invalid literal for int() with base 10: 'abc'
# 種類: ValueError
# --- traceback ---
# Traceback (most recent call last):
# File "...", line 4, in <module>
# value = int("abc")
# ValueError: invalid literal for int() with base 10: 'abc'
複数の except と Exception で包括キャッチ
except は1 つの try に複数並べて書けます。発生したエラーに最初に一致したブロックが実行されるので、具体的なエラー → 一般的なエラーの順に並べるのが定石です。
すべての実行時エラーの親クラスが Exception で、except Exception as e: と書けば想定外のエラーも含めて何でも受け止められます。
numbers = [10, 20, 30]
index = 1
divisor = 0
try:
value = numbers[index]
print(value / divisor)
except IndexError as e:
print(f"インデックス範囲外: {e}")
except ZeroDivisionError as e:
print(f"0 で割れません: {e}")
except Exception as e:
print(f"その他のエラー: {type(e).__name__}: {e}")
# 出力: 0 で割れません: division by zero
Exception を先頭に書かない
Exception はほぼ全ての例外の親なので、先頭に書くと以降の具体的な except が呼ばれなくなります。想定外のエラーだけを吸収する「最後の網」として、いちばん最後に置きましょう。
finally で後処理を必ず実行する
finally: ブロックは、例外が起きても起きなくても必ず実行される後処理の場所です。ファイルや DB 接続のような確実に閉じたいリソースの解放に使います。
else: ブロックは例外が起きなかったときだけ実行されます。使う機会は多くありませんが、「成功した場合のみ後続処理に進む」構成を明示したいときに便利です。
try を実行した結果、例外が起きなかった場合は else に進み、例外が起きた場合は一致する except に進む。いずれの経路でも最後に必ず finally が呼ばれるのがポイント。
# 正常系:else と finally が実行される
a, b = 10, 2
try:
result = a / b
except ZeroDivisionError:
print("0 除算を受け止めました")
else:
print(f"計算成功: {result}")
finally:
print("後処理を実行")
# 出力: 計算成功: 5.0
# 後処理を実行
print("---")
# エラー系:except と finally が実行される
a, b = 10, 0
try:
result = a / b
except ZeroDivisionError:
print("0 除算を受け止めました")
else:
print(f"計算成功: {result}")
finally:
print("後処理を実行")
# 出力: 0 除算を受け止めました
# 後処理を実行
この記事では、try / except による例外処理の基本、as e による例外情報の取得、複数の except と Exception での包括キャッチ、そして finally による後処理を学びました。次の記事では、自分から例外を投げる raise と、自作の例外クラスの作り方を見ていきます。
理解度チェック
まずは1問ずつ答えてみましょう。
Q2次のコードの出力として正しいものはどれですか?a = 100
try:
print(a / 0)
except ZeroDivisionError:
print("caught")
print("end")
Q3try / except / else / finally のうち、例外の有無に関わらず必ず実行されるのはどれですか?