Python : 例外の基本操作編

TwitterFacebookHatena
  • 公開:2021-10-4
  • 更新:2023-10-26
  • 文章量:3670
  • Python

TL;DR

例外とは、エラーが起きたときに実行されるコードのことである。try 文を用いて例外が発生しそうなところに例外処理を追加し、ユーザーに何が起こるのか知らせる。

例外のポイント

  • Python は例外の発生を検知すると強制的にプログラムを終了する
  • 例外の情報とともにトレースバックと呼ばれる例外発生の箇所に関する情報が出力される
  • 例外の補足には try 文を使う
  • 例外が発生したときの処理は except 節に記述する
  • 例外が発生しなかったときの処理は else 文に記述する
  • 例外の発生有無に関係なく実行したい処理は finally 文を記述する

例外の種類

例外クラスは、BaseException という例外を継承している。

BaseException
└── Exception
    ├── ZeroDivisionError
    ├── AttributeError
    ├── TypeError
    └── ValueError

次に示す例外は、すべて Exception のサブクラスである。

例外クラス 意味
IndexError 存在しない範囲のインデックスを指定した
AttributeError 存在しない属性を指定した
KeyError マッピング型で存在しないキーを指定した
TypeError 不正な型を指定した
ValueError 不正な値を指定した
ZeroDivisionError 0 を除算した
BaseException すべての例外のスーパークラス

try 文

try 文は、例外の補足を行う。

例外の発生が事前に予期できる場合は、try 文を利用すると強制終了を避けられる。try 文は、例外処理やクリーンアップ処理を行う際に利用する。

try:
    例外が発生する可能性のある処理
except:
    補足したい例外が発生したときに実行される処理
else:
    例外が発生しなかったときのみ実行
finally:
    例外の発生有無にかかわらず実行
raise:
    意図的に例外を発生させる

except 節

except 節は、例外が検知されたときに実行される。しかし、引数なしの except を指定すると、あらゆる例外型がキャッチされる。

次に示すコードでは、try ブロックで例外が検知され、except ブロックに記述してあるコードが実行されている。

w = [10, 20, 30]
number = 4
try:
    print(w[number])
except:
    print(f'{len(w)} より小さい数でお願いします')
else:
    print('例外は発生しませんでした')
finally:
    print('お疲れ様でした')

# 3 より小さい数でお願いします
# お疲れ様でした

except 節の後ろには、例外型を指定することができる。次のコードは、シーケンスに無効な位置を指定されたときに返される IndexError を指定している。

def n(index_number):
    lang = ['Python', 'Rust', 'Go']
    try:
        return lang[index_number]
    except IndexError:
        return '無効な位置です'

n(5)

# '無効な位置です'

例外型を複数追加したいときは、except 節の後に半角スペースを空け、括弧とカンマ区切りで複数の例外を記述する。(,) のようにカンマ区切りで列挙する。

w = [10, 20, 30]
number = 5
try:
    print(w[number])
except (IndexError, TypeError):
    print('IndexError か TypeError です')

# IndexError か TypeError です

処理を分ける

except 節は複数記述することができる。処理を分けたい場合は、except 節を 任意の数だけ追加するとよい。

w = [10, 20, 30]
number = 'hoge'
try:
    print(w[number])
except IndexError:
    print('IndexError です')
except TypeError:
    print('TypeError です')

# TypeError です

例外型の順番

先に示したように例外クラスは継承の順番があるので、スーパークラスを先に記述すると、サブクラスの例外も補足されてしまう。したがって、継承関係がある例外を複数記述する場合は、サブクラスの例外から記述する。

def num(a, b):
    try:
        i = a / b
        print(i)
    except TypeError:
        print('TypeError')
    except ZeroDivisionError:
        print('ZeroDivisionError')
    except Exception:
        print('Exception')
num(8, 'hoge')

# TypeError

as キーワード

例外の詳細情報を獲得したい場合、except 節の後ろに、as キーワードと変数名をつけ、except ブロック内に埋め込むと、例外オブジェクトの内容を表示することができる。

except (例外型の指定) as 変数名

次のコードは、除数が 0 になり計算できないので、ZeroDivisionError が発生し、それを捕獲している。

def num(a, b):
    try:
        i = a / b
        print(i)
    except ZeroDivisionError as er:
        print(f'{er}')
num(8, 0)

# division by zero

次に示すコードでは、シーケンスに無効な位置を指定されたときに返される IndexError を捕獲し、メッセージが表示される。

w = [10, 20, 30]
number = 5
try:
    print(w[number])
except (IndexError, TypeError) as er:
    print(f'{er}')

# list index out of range

else 節 と finally 節

else 節は、例外が発生しなかったときに実行される。正常終了時のみの実行である。

finally 節は、例外の有無に関わらず必ず実行される。

try ブロックで例外が検知されない場合は、except ブロックは実行されず、try と else と finally が実行される。

w = [10, 20, 30]
number = 2
try:
    print(w[number])
except:
    print(f'{len(w)} より小さい数でお願いします')
else:
    print('例外は発生しませんでした')
finally:
    print('お疲れ様でした')

# 30
# 例外は発生しませんでした
# お疲れ様でした

raise 文

raise 文で例外を発生させることができる。raise で指定できる例外は、Exception を継承した例外クラスと例外オブジェクトである。

raise 例外クラス(メッセージ)
raise NameError('hoge')

# NameError: hoge
try:
    raise TypeError('不正な型です')
except TypeError as er:
    print(er)

# 不正な型です

例外を再送出する

例外が発生した際、処理を行った後に、再び例外処理を実行したい場合は、例外を再送出させる。

def num(a, b):
    try:
        i = a / b
        print(i)
    except Exception as er:
        print('例外発生')
        raise er

num(8, 0)

# 例外発生
# ZeroDivisionError: division by zero

Python : 例外の基本操作編