【Python】例外処理の基本(exception)
の基本-_-try-except-raise-_.jpg)
Python の例外処理(exception)の基本について解説します。
目次
例外処理(exception)
例外(exception)は、プログラムの処理を中断させる原因となる問題のことです。多くのプログラミング言語と同様、Python にも例外処理の仕組みがあります。
例外が発生した場合は、適切な対応を行った上でプログラムを継続させたり、安全に終了させたりすることが重要です。例外処理のコードは「例外ハンドラ」と呼ばれ、例外をキャッチしない場合は上位に伝わり、適切なハンドラが見つかるまで伝播します。
適切な例外ハンドラがない場合、Python はエラーメッセージと発生場所を表示し、プログラムを強制終了します。以下のコードではインデックスエラー(IndexError)が発生する例です。
data_list = ["A", "B", "C"] print(data_list[5])
【実行結果例】
Traceback (most recent call last):
File "D:/~/exception_sample.py", line 2, in <module>
print(data_list[5])
IndexError: list index out of range
Process finished with exit code 1上記例では、インデックス範囲外のアクセスでエラーが発生し、プログラムが強制終了します。例外が起きた際には、プログラマが適切な処理を記述してプログラムを「継続」または「終了」させることが必要です。
この記事では、Python の例外処理の基本について紹介します。
例外処理の基本的な方法
ここからは、例外処理の基本について説明します。
例外のキャッチ(try...except...)
使い方の基本
例外を処理するには、例外が発生する可能性があるコードを try で囲み、except で例外をキャッチします。以下の例で基本的な使い方を確認しましょう。
data_list = ["A", "B", "C"]
try:
print(data_list[5])
except IndexError as ex:
print(ex)
print("end")【実行結果】 list index out of range end
上記例では print(data_list[5]) が IndexError をスローし、except ブロックでキャッチします。print(ex) によりエラーメッセージが出力され、その後の print("end") も実行されていることから、プログラムは例外が発せしても終了せずに次の処理へ進んでいることが分かります。
業務アプリケーション等では、例外が発生したからと言ってプログラムが停止しては困ります。このような場合には、例外に対するエラーを表示する、ログに出力するなどの処理をしたうえで、アプリケーションの動作としては継続します。
as で例外を変数に受け取りますが変数名については特に決まりはありません。ex や e などがよく使用されます。受け取った例外 ex を確認することで例外の詳細を確認することができます。
例外が発生したらプログラムを終了する
例外が発生した場合、必要があればプログラムを終了する場合もあります。
import sys
data_list = ["A", "B", "C"]
try:
print(data_list[5])
except IndexError as ex:
print(ex)
sys.exit(1)
print("end")【実行結果】 list index out of range Process finished with exit code 1
上記例では、例外が発生したら例外を表示して sys.exit で終了しています。
プログラムを停止するにしても安全に処理させるには、リソースの解放など処理が必要な場合があります。そのような際には、例外をキャッチし、必要な処理を行ってから安全に終了します。
複数の例外のキャッチ
Python には、多くの例外クラスが用意されています。Pythonドキュメントの「例外のクラス階層」で組み込みの例外クラス階層を確認できます。
Python プログラミングでは、使用するモジュールによって発生する例外が異なるため、複数の例外が発生する可能性があります。Python では except を列挙することができ、複数の例外をキャッチできます。
data_list = ["A", "B", "C"]
while True:
input_value = input("input index (q to quit): ")
if input_value == "q":
break
try:
index = int(input_value)
print(data_list[index])
except IndexError as ex:
print(f"bad index : {ex}")
except ValueError as ex:
print(f"bad value : {ex}")【実行結果】 input index (q to quit): 0 A input index (q to quit): 1 B input index (q to quit): 2 C input index (q to quit): 3 bad index : list index out of range input index (q to quit): one bad value : invalid literal for int() with base 10: 'one' input index (q to quit): q
上記例では、リストのインデックスが範囲外の場合は IndexError が、型変換できない値が入力された場合は ValueError がスローされ、それぞれのexceptでキャッチされています。このように複数の例外を列挙して処理できます。
独自例外の作成と例外のスロー(raise)
独自の例外を作成して処理したい場合は、例外クラスを作成して raise でスローすることが可能です。以下は、独自の例外を作成する例です。
class MyException(Exception):
pass
def my_original_method(value):
if value < 0:
raise MyException("minus value is not allowed")
else:
return value
def main():
value = -10
try:
print(my_original_method(value))
except MyException as ex:
print(ex)
if __name__ == "__main__":
main()【実行結果】 minus value is not allowed
上記例では、MyException クラスを Exception を継承して作成し、my_original_method 関数内で負の数値が渡された場合にスローしています。例外のスローは、エラーメッセージを raise に渡して実行します。except で独自例外をキャッチすることで、例外処理が可能です。
実際のアプリケーション開発では、機能で独自 Exception のクラスを作成することで、どこで例外が起こったか、どのような例外が起こったかを分かりやすくすることがよく行われます。上記例では、ただ Exception を継承しただけの中身のないクラスですが、クラスに独自機能や情報を含めることで様々な情報を持たせることが可能です。
Python の例外は、BaseException クラスから派生したクラスである必要があり、一般的には、Exception クラスを継承して独自例外を作成します。例外のクラス階層については、Pythonドキュメントの「例外のクラス階層」を参照してください。
例外処理での注意事項
except Exception で全ての例外をキャッチすべきではない
例外処理では「except Exception」で全ての例外をキャッチすることは極力避けるべきです。以下は、上述のプログラムを「except Exception」に書き換えた例です。
data_list = ["A", "B", "C"]
while True:
input_value = input("input index (q to quit): ")
if input_value == "q":
break
try:
index = int(input_value)
print(data_list[index])
except Exception as ex:
print(f"exception: {ex}")【実行結果】 input index (q to quit): 0 A input index (q to quit): 1 B input index (q to quit): 2 C input index (q to quit): 3 exception: list index out of range input index (q to quit): one exception: invalid literal for int() with base 10: 'one' input index (q to quit): q
このプログラムでは「except Exception」が全ての例外をキャッチします。except Exception は、特定の例外に限らず全ての例外をまとめてキャッチできるため、プログラムは動作しますが、この方法は推奨しません。
理由として「想定外の例外に対する処理ほど危険なものはない」ためです。プログラマは、自分のプログラムで発生しうる例外を洗い出し、それに対する処理を明確に記載するべきであり、これはプログラム品質向上に不可欠な作業です。
全ての例外を想定することは難しいため、必要な例外を個別にキャッチした後に「except Exception」でそのほかを処理するのはやむを得ない場合もあり、私も簡易的なプログラム作成ではそういった対応をすることはあります。
しかし、何が発生するかわからないからと言って安易に全ての例外をキャッチすることは適切ではありません。特に重要なアプリケーションでは例外処理は慎重に検討をするように心がけてください。このような姿勢は、Python に限らずプログラマのとして心構えとして重要です。
まとめ
Python の 例外処理(exception)の基本として、try、except、raise の使い方、複数の例外処理、独自例外作成について解説しました。また「exept Exception」で全ての例外を安易にキャッチすることは推奨しないことについても説明しています。
例外が発生した場合、適切な通知やプログラム停止など、プログラマが対応を十分に検討して対処することが重要です。例外処理を適切に処理できるようになって、安全で高品質なプログラム開発を目指しましょう。
上記で紹介しているソースコードについては GitHub にて公開しています。参考にしていただければと思います。

