Pythonを含む全てのプログラミングにおいて、エラーと例外処理の扱いは、プログラムの堅牢性に密接に関わる重要なテクニックだ。
今回はPythonの例外処理の書き方についてまとめていく。
コンテンツ
エラー発生時の動作について
まずはPythonのエラーについて見てみよう。
int関数は引数に指定した小数などのデータ型を整数に変換する関数だ。
int(1.1) # 1
int('string') # エラー発生!
# ValueError: invalid literal for int() with base 10: 'string'
1行目、引数に1.1を指定するとint関数によって、整数1が返される。
3行目、引数に文字列を指定するとどうなるか?
これはエラーとなり、エラー結果が出力され、プログラムはエラー発生時点で停止してしまう。
例外処理でエラー発生時のプログラム停止を避ける
先述のとおり、プログラムはエラーが発生すると停止してしまう。
これを避けるため例外処理を実装し、もしエラーが発生したら別の処理に切り替え、プログラムを続行させるサンプルコードを書いていこう。
まず、以下のような関数add_intを定義する。
関数呼び出しの際、誤って文字列を引数に指定してしまうとエラーが発生し、処理は中断されてしまう。
def add_int(x, y):
return x + y
add_int(1, '1') # TypeError
このadd_intに例外処理を加えた例が下記のコードだ。
def add_int(x, y):
try:
return x + y
except:
return x, y
add_int(1, 1) # 2
add_int(1, '1') # (1, '1')
まず、デフォルトでおこなう処理をtry:以降に書く。
そして例外処理、except:以降にはエラー発生時に実行する処理を書けばOKだ。
7行目、一つ目の関数呼び出しではどちらの引数も整数が指定されているので、try以降の処理に移り、x + yが実行される。
この時、特にエラーが発生しなければexcept以降の処理は無視される。
9行目では、第二引数が文字列として指定されている。
こちらも処理の流れは、まずtry以降のx + yが実行されるのだが、今回は整数と文字列の計算となるのでエラーが発生する。
ここで処理が例外のexceptへと移り、引数をそのまま返す5行目のreturn文が実行されるというわけだ。
エラーの種類によって例外処理を分ける
プログラムのエラーには様々な原因、エラーの種類がある。
例えば以下のような割り算をする関数div_intがあったとする。
引数に文字列を与えるとTypeErrorを起こすが、0を指定すると0除算によるZeroDivisionErrorが発生する。
def div_int(x, y):
return x / y
div_int(1, '1') # TypeError
div_int(1, 0) # ZeroDivisionError
こうした様々なエラーが考えられる場合、例えばTypeErrorの時はAという処理を、NameErrorの時はBという処理を、といったエラーの種類に応じた処理分けをおこなうこともできるのだ。
では早速例を見てみよう。
def div_int(x, y):
try:
return x / y
except TypeError:
print('処理A')
except ZeroDivisionError:
print('処理B')
div_int(1, '1') # 処理A
div_int(1, 0) # 処理B
文法は単純で、exceptの後にエラー種別名を書くだけで良い。
発生したエラーに応じて処理が切り替わるという仕組みだ。
エラー発生の有無に関わらず処理を実行する
ここまでtryとexceptによる処理の切り分けを見てきたが、エラー発生の有無に関わらず共通した処理をおこなわせることもできる。
以下の例のとおり、finallyを使うと以降のコードが必ず実行されるのだ。
def div_int(x, y):
try:
return x / y
except TypeError:
print('処理A')
except ZeroDivisionError:
print('処理B')
finally:
print('test')
div_int(1, '1') # 処理Aの後にtestが出力される。
div_int(1, 1) # 1.0が返され、testが出力される。
まとめ
冒頭に記述したとおりプログラムの例外処理は非常に重要だ。
業務用アプリケーションなど、デリケートなシステムを構築する際などは原則的にtry・except文を使用する必要があるだろう。