#!/usr/bin/env python # coding: utf-8 # # 例外 # ## 例外の捕捉 # 以下のコードは数値を$0$で割るため、実行するとエラー(例外)が発生する。 # In[1]: 2. / 0 # プログラム中でエラーが発生したときは、例外クラスのオブジェクトが作成・送出される。例えば、上の例では[ZeroDivisionError](https://docs.python.org/ja/3/library/exceptions.html#ZeroDivisionError)という例外クラスのオブジェクトが`'float division by zero'`というメッセージ付きで送出されている。 # # プログラムの実行中に例外が発生するとPythonインタプリタの実行が直ちに停止されるが、 [try](https://docs.python.org/ja/3/reference/compound_stmts.html#the-try-statement)文およびexcept節を用いて、例外をプログラム中で捕捉することも可能である。 # In[2]: try: 2. / 0 except ZeroDivisionError as e: print('ゼロ除算:', e) # try文を用いても、except節で指定した例外クラス以外の例外が発生した場合は、except節は実行されずPythonインタプリタの実行が止まってしまう。以下のプログラムで発生する例外は[OverflowError](https://docs.python.org/ja/3/library/exceptions.html#OverflowError)であるため、ZeroDivisionErrorに関するexcept節では捕捉しきれない。 # In[3]: try: 2. ** 1024 except ZeroDivisionError as e: print(e) # except節を複数並べることで、異なる複数の例外に対する処理を記述できる。 # In[4]: try: 2. ** 1024 except ZeroDivisionError as e: print('ゼロ除算:', e) except OverflowError as e: print('オーバーフロー:', e) # In[5]: try: 2. / 0 except ZeroDivisionError as e: print('ゼロ除算:', e) except OverflowError as e: print('オーバーフロー:', e) # except節に例外クラスをタプルとしてまとめることで、異なる複数の例外に対する処理をまとめて記述できる。 # In[6]: try: 2. ** 1024 except (ZeroDivisionError, OverflowError) as e: print('例外:', type(e), e) # In[7]: try: 2. / 0 except (ZeroDivisionError, OverflowError) as e: print('例外:', type(e), e) # なお、ZeroDivisionErrorやOverflowErrorなどの組み込み例外の基底クラスは[Exception](https://docs.python.org/ja/3/library/exceptions.html#Exception)であるため、except節でExceptionクラスを指定すると、異なる種類の例外をまとめて捕捉できる。 # In[8]: try: 2. ** 1024 except Exception as e: print('例外:', type(e), e) # In[9]: try: 2. / 0 except Exception as e: print('例外:', type(e), e) # ## 例外の送出 # [raise](https://docs.python.org/ja/3/reference/simple_stmts.html#raise)文を用いると、自分で実装したコードの中から例外を送出できる。 # In[10]: def timestamp(hour, minute, second): if hour < 0 or 24 <= hour: raise ValueError("引数hourは0 <= hour < 24を満たす必要があります") if minute < 0 or 60 <= minute: raise ValueError("引数minuteは0 <= minute < 60を満たす必要があります") if second < 0 or 60 <= second: raise ValueError("引数secondは0 <= second < 60を満たす必要があります") return hour * 3600 + minute * 60 + second # In[11]: timestamp(2, 43, 70) # 関数の呼び出し側にtry文を埋め込み、例外を捕捉することも可能である。 # In[12]: try: timestamp(48, 0, 0) except Exception as e: print('例外:', type(e), e) # 例外クラスを自分で定義することもできる。ユーザ定義の例外クラスは[Exception](https://docs.python.org/ja/3/library/exceptions.html#Exception)を継承する必要がある。 # In[13]: class TimestampError(Exception): pass def timestamp(hour, minute, second): if hour < 0 or 24 <= hour: raise TimestampError("引数hourは0 <= hour < 24を満たす必要があります") if minute < 0 or 60 <= minute: raise TimestampError("引数minuteは0 <= minute < 60を満たす必要があります") if second < 0 or 60 <= second: raise TimestampError("引数secondは0 <= second < 60を満たす必要があります") return hour * 3600 + minute * 60 + second # In[14]: timestamp(1, 95, 22) # 今回の引数チェックの場合、`hour`, `minute`, `second`のそれぞれに対し、別の例外クラスを定義するのも一案である。 # In[15]: class TimestampError(Exception): pass class TimestampHourError(TimestampError): pass class TimestampMinuteError(TimestampError): pass class TimestampSecondError(TimestampError): pass def timestamp(hour, minute, second): if hour < 0 or 24 <= hour: raise TimestampHourError("引数hourは0 <= hour < 24を満たす必要があります") if minute < 0 or 60 <= minute: raise TimestampMinuteError("引数minuteは0 <= minute < 60を満たす必要があります") if second < 0 or 60 <= second: raise TimestampSecondError("引数secondは0 <= second < 60を満たす必要があります") return hour * 3600 + minute * 60 + second # In[16]: try: timestamp(2, 68, 0) except Exception as e: print('例外:', type(e), e) # なお、デバッグ目的であれば[assert](https://docs.python.org/ja/3/reference/simple_stmts.html#the-assert-statement)文を使い、引数の値をチェック(テスト)して、違反していたら[AssertionError](https://docs.python.org/ja/3/library/exceptions.html#AssertionError)を送出することもできる。 # In[17]: def timestamp(hour, minute, second): assert 0 <= hour < 24, "引数hourは0 <= hour < 24を満たす必要があります" assert 0 <= minute < 60, "引数minuteは0 <= minute < 60を満たす必要があります" assert 0 <= second < 60, "引数secondは0 <= second < 60を満たす必要があります" return hour * 3600 + minute * 60 + second # In[18]: timestamp(2, 43, 70) # ## よく見かける例外 # 文法エラー # In[19]: 2 / / 1 # インデントの間違い # In[20]: for i in range(10): if i % 2 == 0: print('even') # オーバーフロー # In[21]: 2. ** 1024 # 未定義の変数 # In[22]: a * 2 # 範囲外のインデックス # In[23]: x = [1, 2, 3] x[4] # キーが見つからない # In[24]: y = {'one': 1, 'two': 2, 'three': 3} y['four'] # 型の不整合 # In[25]: x + y # ファイルが見つからない # In[26]: open('hoge.txt') # --- # # [Python早見帳](https://chokkan.github.io/python/) © Copyright 2020-2022 by [岡崎 直観 (Naoaki Okazaki)](https://www.chokkan.org/). この作品はクリエイティブ・コモンズ 表示 - 非営利 - 改変禁止 4.0 国際 ライセンスの下に提供されています。クリエイティブ・コモンズ・ライセンス