とりゅふの森

GCPデータエンジニアとして生きる

【Python入門】例外の発生方法と、独自例外クラス

f:id:true-fly:20210727234256p:plain

今回はPythonにおける例外の発生方法と、例外クラスについてまとめました。 以下の記事の続きになります。例外処理がそもそもわからないという方はまずはこちらをどうぞ。

www.true-fly.com

本記事のコードはすべて、Python 3.7.6で実行しています。

入門 Python 3 第2版

入門 Python 3 第2版

Amazon

例外の発生方法

例えば以下のコードがあったとします。divede()は、n÷mを計算し、オプションパラメータのrに指定された桁数で丸めて標準出力するといった関数です。
rに値を入れる場合、0以上の自然数のみ入力を許可し、それ以外の場合は例外を発生させたい場合、以下のようになります。

def divide(n, m, r=None):
    ans = n / m
    if r is not None:
        if not(type(r) == int and r >= 0):
            raise ValueError('パラメータ:r は0以上の自然数を指定してください')
        ans = round(ans, r)
        round
    print(ans)


print('> 100 / 7')
divide(100, 7)
print('> 100 / 7 (1桁)')
divide(100, 7, 1)
print('> 100 / 7 (-1桁)')
try:
    divide(100, 7, -1)
except Exception as e:
    print('{}, {}'.format(e.__class__, e))
print('> 100 / 7 (一桁)')
try:
    divide(100, 7, "-1")
except Exception as e:
    print('{}, {}'.format(e.__class__, e))
> 100 / 7
14.285714285714286
> 100 / 7 (1桁)
14.3
> 100 / 7 (-1桁)
<class 'ValueError'>, パラメータ:r は0以上の自然数を指定してください
> 100 / 7 (一桁)
<class 'ValueError'>, パラメータ:r は0以上の自然数を指定してください

5行目のraise ValueError('パラメータ:r は0以上の自然数を指定してください')で、意図的に例外を発生させています。このように自分で実装したロジック内で例外を発生させ、例外処理を呼び出し元で処理したい場合は、

raise 例外クラス()

と書きます。Javaではこのraiseの部分がthrowで書くので、Javaに親しいエンジニアからは「例外を投げる」って呼ばれることも多いです。

独自例外クラスを定義する

例外を投げるときに、ValueErrorなどの組み込み例外を利用することができますが、自分で独自例外クラスを定義して例外を投げることもできます。ケースによって例外クラスを使い分けることで、例外処理時に例外クラスで処理を場合分けできます。

class RoundTypeError(Exception):
    pass


class RoundRangeError(Exception):
    pass


def divide(n, m, r=None):
    MSG = 'パラメータ:r は0以上の自然数を指定してください。'
    ans = n / m
    if r is not None:
        if type(r) != int:
            raise RoundTypeError(MSG)
        if r < 0:
            raise RoundRangeError(MSG)
        ans = round(ans, r)
        round
    print(ans)


print('> 100 / 7')
divide(100, 7)
print('> 100 / 7 (1桁)')
divide(100, 7, 1)
print('> 100 / 7 (-1桁)')
try:
    divide(100, 7, -1)
except Exception as e:
    print('{}, {}'.format(e.__class__, e))
print('> 100 / 7 (一桁)')
try:
    divide(100, 7, "-1")
except Exception as e:
    print('{}, {}'.format(e.__class__, e))
> 100 / 7
14.285714285714286
> 100 / 7 (1桁)
14.3
> 100 / 7 (-1桁)
<class '__main__.RoundRangeError'>, パラメータ:r は0以上の自然数を指定してください。
> 100 / 7 (一桁)
<class '__main__.RoundTypeError'>, パラメータ:r は0以上の自然数を指定してください。

RoundTypeErrorRoundRangeErrorという2つの例外クラスを定義してみました。それぞれ、Exceptionを継承したクラスで、クラス内にはpassのみを書くことで、実装を省略しています。Exceptionを継承することで、raiseで例外を投げることができるようになります。

まとめ

今回は例外を発生させる方法と、独自例外クラスの定義方法についてまとめました。
簡単なサンプルですが、つかみにくい例外、例外処理の理解への一助になればと思います。