例外処理
例外処理とは
例外は「戻り値とは異なる形でメソッドからエラーを返す仕組み」である。例外処理(try-except)を利用すると、処理の途中で例外(エラー)が発生したときに、その処理を中断して別の処理に切り替えることによって発生した例外(エラー)にうまく対処できるようになる。
例えば、Pythonで「1/0」を実行すると組み込み例外「ZeroDivisionError」が発生し、例外が発生した箇所で処理が中断する。
num = 1 / 0
print("この部分は処理されない")
# Traceback (most recent call last):
# File "C:\Users\yuki\main.py", line 1, in <module>
# num = 1 / 0
# ~~^~~
# ZeroDivisionError: division by zero
try-except文を用いると、例外が発生した箇所で処理を一時中断し、except節から処理を再開する。
try:
num = 1 / 0
print("この部分は処理されない")
except:
print("例外が発生しました。")
# 例外が発生しました。
exceptの後に例外名を指定すると、例外の種類ごとに処理を振り分けることができ、asの後に設定した変数でエラーメッセージが受け取れる。
try:
num = 1 / 0
print("この部分は処理されない")
except ZeroDivisionError as e:
print("ZeroDivisionErrorが発生しました。")
print(f"Error: {e}")
except TypeError as e:
print("TypeErrorが発生しました。")
print(f"Error: {e}")
except ValueError as e:
print("ValueErrorが発生しました。")
print(f"Error: {e}")
# ZeroDivisionErrorが発生しました。
# Error: division by zero
さらに、elseを使うとエラーが発生しなかった場合に実行される処理を、finallyを使うと最後に必ず実行される処理を記述できる。
try:
num = 1 / 2
except ZeroDivisionError as e:
print("ZeroDivisionErrorが発生しました。")
print(f"Error: {e}")
except TypeError as e:
print("TypeErrorが発生しました。")
print(f"Error: {e}")
except ValueError as e:
print("ValueErrorが発生しました。")
print(f"Error: {e}")
else:
print('例外が発生しませんでした。')
finally:
print('以上')
# 例外が発生しませんでした。
# 以上
上記の処理をフローチャートで表現すると次のようになる。
例外を発生させる
raise文を使うと、自分で例外を発生させることもできる。
raise TypeError('型エラーが発生しました。')
# Traceback (most recent call last):
# File "C:\Users\yuki\main.py", line 1, in <module>
# raise TypeError('型エラーが発生しました。')
# TypeError: 型エラーが発生しました。
前述のZeroDivisionError、TypeError、ValueErrorなどはPython標準の組み込み例外だが、標準の例外を継承することでユーザー独自のカスタム例外を作ることもできる。
class CustomExceptinon(Exception):
pass
raise CustomExceptinon('カスタム例外が発生しました。')
# Traceback (most recent call last):
# File "C:\Users\yuki\main.py", line 4, in <module>
# raise CustomExceptinon('カスタム例外が発生しました。')
# CustomExceptinon: カスタム例外が発生しました。
例外のエスカレーション
実行時に例外が発生すると、処理を中断してexcept節を探して呼び出し元にエスカレーションしていく。except節が同メソッド内になければ呼び出し元のメソッドに、そこにもなければさらに上位の呼び出し元のメソッドに…、というように遡って探索する。最上位の呼び出し元まで探してexcept節がなければ、エラーを吐いて処理終了となる。
def func1():
func2()
def func2():
try:
print(1 / 0)
except:
print('func2関数内で例外をキャッチ!')
func1()
# func2関数内で例外をキャッチ!
def func1():
try:
func2()
except:
print('func1関数内で例外をキャッチ!')
def func2():
print(1 / 0)
func1()
# func1関数内で例外をキャッチ!
def func1():
func2()
def func2():
print(1 / 0)
func1()
# Traceback (most recent call last):
# File "C:\Users\yuki\main.py", line 7, in <module>
# func1()
# File "C:\Users\yuki\main.py", line 2, in func1
# func2()
# File "C:\Users\yuki\main.py", line 5, in func2
# print(1 / 0)
# ~~^~~
# ZeroDivisionError: division by zero