【初心者向け】例外処理とは何か?Pythonを使って例外処理を記述しよう!

例外処理

例外処理とは、プログラムがある処理を実行している途中で、なんらかの異常が発生した場合に、現在の処理を中断し、別の処理を行うことです。
例外処理を記述することで、予期していなかったエラーに対応できるプログラムを書くことができます。

予期していないエラーとはなんでしょうか?
実は、エラーは大きく分けて2種類あります。
1. 構文エラー(Syntax Error)
2. 例外(Exception)

まずは、1. 構文エラー(Syntax Error)から見ていきましょう。

if 10 > 5

上記コードは次のようなエラーが出ます。

File "<stdin>", line 1
if 10 > 5
        ^
SyntaxError: invalid syntax

上記のように、構文エラー: 無効な構文と言ったエラーが表示されており、if文の:がないためにエラーが起きています。
構文エラーは致命的なエラーであり、構文エラーがある場合プログラムは実行できません。
ファイル名及び、行数などを知らせてくれるためにエラーがどこかは発見しやすいです。

次は、2. 例外(Exception)に関してです。
例外処理を記述することで、予期せぬエラーに対応できるプログラムを書くことができます。
予期せぬエラーというのは、つまり想定外の事象によりプログラムが動作しなくなってしまうことです。
これを例外と呼びます。
例外には、IndexErrorやTypeErrorやNameErrorやZeroDivisionErrorなどがあります。
これらの例外エラーは構文エラーとは違って致命的ではないので、例外処理を記述していればプログラムは実行し続けることが出来ます。

それでは下記のプログラムを読んでみてください。

i = input()
input_num = int(i) 

result = 5 / input_num
print(result)

例えばもし、ここでユーザーが5とか入力した場合だと問題ないですが、ユーザーが0を入力したらどうなるでしょうか?
Pythonでは0で割ると、 ZeroDivisionErrorという例外を発生します。
まずここでは、先ほどのプログラムに例外処理を記述して、0で割られた時の例外処理を記述してみましょう。
例外処理は、例外が発生する可能性がある箇所をtryブロック内に記述し、exceptで例外を捕捉します。

try:
    5/0
except ZeroDivisionError:
    print('ZeroDivisionError!!')

上の例は、ゼロ除算時にZeroDivisionErrorが発生し、それをexcept節で捕捉(キャッチ)しています。

以下のようにエラーで待ち構えている場合は意味がないので注意が必要です。

try:
    5/0
except IndexError:
    print('indexError!!')

# print("値を入力してください: ")
i = input()
input_num = int(i) 
try:
    result = 5 / input_num
    print(result)
except ZeroDivisionError:
    print('ZeroDivisionError!!')

上記のプログラムに例外処理を施す場合には以下のように記述します。

i = input()
input_num = int(i) 

try:
    result = 5 / input_num
    print(result)
except ZeroDivisionError:
    print('ZeroDivisionError!!')

例外処理の構文

さて、例外のイメージがついたところで、例外処理の構文を見てみます。
下記のように、例外処理を利用するには、try exceptを用います。
tryの内部には、例外が発生しそうなプログラムを記述します。

# 例外処理の構文

try:
    例外が発生しそうなプログラム
except:
    例外が起きた時の処理

exceptには、OSErrorやValueError,ZeroDivisionError, NameError, TypeErrorなど例外を記述することができます。

例外オブジェクトを捕捉する

例外に関する情報は以下の形式で取得できます。
as 一時変数名
では、サンプルを見てみましょう。

try:
    # バグ1
    i = input()
    input_num = int(i)
    result = 5 / input_num # 5 / 2 => 2.05
    print(result)

    # バグ2
    a = "a"
    b = 5
    print(a+b)

except (TypeError, ZeroDivisionError, KeyError) as e:
    print(type(e))

複数の例外を捕捉する

例外は、複数のexcept節を用いて発生した例外に応じた処理をすることもできます。
また、上記のサンプルのように、()に複数の種類を1か所で捕捉して書くこともできます。

try:
    print('処理')
except KeyError as e:
    print('KeyError')
except ZeroDivisionError as e:
    print('ZeroDivisionError')
except:
    print('Error')

else / finally

forやwhile文同様に、tryブロックが例外を発生せずに最後まで処理が進んだ場合、elseブロックが実行されます。
また、tryブロックが例外を発生しなくても、実行されるfinallyも定義できます。
finallyは「例外の発生に関係なく最後に処理を実行します。
また、finallyは例外が発生しても例外処理の後に必ず実行されます。

try:
    print('処理')
except KeyError as e:
    print('KeyError')
except ZeroDivisionError as e:
    print('ZeroDivisionError')
else:
    print('問題なく処理が実行されました')
finally:
    print('処理2')

まとめ

例外処理を記述することで、バグの出にくいプログラムを書くことができます。
個人で開発している分ですと、あまり気にしなくて良いかもしれませんが、実務の場合は基本1つのプロジェクトを複数人で開発するものです。
もし、プログラムにバグがあると、会社の利益を損なう可能性もありますし、医療システム等であれば、命に関わってきます。
ですので、バグの少ないプログラムを書くためには、例外処理を使うようにしましょう。