[Python入門]例外の送出と例外クラスPython入門(2/2 ページ)

» 2019年09月10日 05時00分 公開
[かわさきしんじDeep Insider編集部]
前のページへ 1|2       

例外クラス

 次にPythonが標準で提供している組み込み例外について少し見ておこう。前回も触れたが、例外を表すクラスはさまざまに分類されて、継承階層を構成している。

例外クラスの継承階層(一部) 例外クラスの継承階層(一部)

 その頂点にある(例外クラスの大本の基底クラスとなっている)のがBaseExceptionクラスだ。このクラスからはシステムの終了に関する例外クラスが幾つか派生しているが、それ以外にもう一つ重要なクラスが派生している。それがExceptionクラスだ。Exceptionクラスは、Pythonプログラムの実行時に発生するほぼ全ての例外を表す例外クラスの基底クラスとなる。

 このような階層構成となっているのは、恐らくシステム終了(sysモジュールのexitメソッドによるPython環境の終了や、ユーザーのキーボード操作によるプログラムの中断)などの状況を、通常の例外とは別の継承階層に位置させることで、プログラム実行時に発生することが想定できる例外は「except:」節や「except Exception:」節で一挙に捕捉できるようにする一方で、システム終了という特殊な状況は別のexcept節(例外ハンドラ)で処理できるようにしたいからだろう。

try:
    # 何かの処理
except ……:
    # 個別の例外を処理する例外ハンドラ
except Exception as e:
    # 個別に指定した以外の例外を一括して処理する例外ハンドラ
except:
    # システム終了に関する例外(異常事態)を処理する例外ハンドラ

プログラム実行時に発生することが想定される例外と、システム終了となるような事態とを切り分けて処理を実行できる

 Pythonに組み込みの例外クラスを幾つか以下にまとめておこう。全ての例外クラスについてはPythonのドキュメント「組み込み例外」を参照されたい。以下の表ではクラス階層を「→」によるインデントで表している(例:ArithmeticErrorクラスの派生クラスにはZeroDivisionErrorクラスがある)。

例外クラス 説明
BaseException 全ての例外クラスの基底クラス
→Exception システム終了に関連する例外クラス以外の組み込みクラスの基底クラス
→AttributeError オブジェクトの属性を参照しようとしたときに、その属性がなかったり、属性への代入が失敗したりすると発生する
→ArithmeticError 算術演算に関連する例外の基底クラス
→→ZeroDivisionError 0を除数として除算(割り算)を行ったときに発生する例外(例:「1 / 0」)
→LookupError リストや辞書などのインデックスやキーで存在しないものを指定した場合に発生する例外の基底クラス
→→IndexError リストなどで指定したインデックスに対応する要素がない場合に発生する例外(例:「'str'[4]」)
→→KeyError 辞書などで指定したキーに対応する値がない場合に発生する例外(例:「{}['key']」)
→NameError 指定した名前がローカルスコープやグローバルスコープに見つからなかったときに発生する例外(例:「print(undefine_var)」)
→RecursionError 関数の再帰呼び出しなどで、再帰の上限を超えたときに発生する例外
→StopIterationError イテレータが返送する要素が尽きたときに、それ以降、イテレータから要素を取り出そうとすると発生する例外
→SyntaxError 構文エラーの基底クラス
→→IndentationError ブロック内のコードのインデントが統一されていないと発生する例外
→→→TabError ブロックのインデントにタブ文字と半角空白文字が混用されているときに発生する例外
→TypeError 演算や操作の対象となったオブジェクトが、それをサポートしていないときに発生する例外(例:「1 + '2'」)
→ValueError 演算や操作の対象となったオブジェクトが型は合っているが、その値が適切でないときに発生するエラー(例:「int('one')」)
Pythonに組み込みの例外クラス(抜粋)

 この表に示した以外にも多くのクラスがPythonでは標準で提供されている。多くの場合は、それらを使って、プログラムで発生した問題を表せるが、自分で独自の例外を定義できるとよいこともある。

例外クラスの定義

 例外クラスを独自に定義するときには注意する点が一つある。それは、他の例外クラスと同様に、Exceptionクラス(またはその派生クラス)を継承するクラスとすることだ。それを除けば、後は通常のクラスと同様だ。

 例えば、先ほどのMyStackクラスでは、IndexError例外を送出していたが、その代わりにEmptyStackError例外を送出するようにしてみよう。これにはもちろんEmptyStackErrorクラスを定義する必要がある。なお、PEP 8では、例外クラスの最後には「Error」を付けることが推奨されている。そこで、ここでも最後に「Error」を付けるようにしている。

 そのコードは簡単だ。

class EmptyStackError(Exception):
    pass

EmptyStackErrorクラスの定義

 一番簡単には、上のクラスを定義するだけで、独自の例外クラスを作成できる。そこで、先ほどのMyStackクラスも変更してみよう。

class EmptyStackError(Exception):
    pass

class MyStack:
    def __init__(self):
        self.stack = []
    def push(self, item):
        self.stack.append(item)
    def pop(self):
        if len(self.stack) == 0:
            raise EmptyStackError('stack is empty')
        return self.stack.pop()

EmptyStackError例外クラスとそれを使用するMyStackクラス

 では、先ほどと同じコードでこれらのクラスの動作を確認してみよう。

mystack = MyStack()
mystack.push(0)
print(mystack.pop())
print(mystack.pop())

EmptyStackErrorクラスとMyStackクラスの動作を確認するコード

 実行結果は次のようになる。

実行結果 実行結果

 EmptyStackErrorクラスをカスタマイズするとしたら、インスタンス生成時に引数を渡さなくても「stack is empty」などのメッセージがインスタンス変数argsにセットされると便利かもしれない。これを行うには次のようなコードを書けばよい。

class EmptyStackError(Exception):
    def __init__(self, *args):
        if len(args) == 0# 引数が渡されなかったら基底クラスの__init__
            super().__init__('stack is empty'# メソッドにメッセージを渡す
        else# 引数が渡されたら全てを基底クラスの__init__メソッドに渡す
            super().__init__(args)

引数なしで「EmptyStackError()」としてインスタンスが生成されたら「stack is empty」というメッセージを設定するようにカスタマイズしたEmptyStackErrorクラス

 こうすることで、以下のように「raise EmptyStackError」と書くだけで、「stack is empty」というメッセージ付きで例外が発生するようになる(既に述べたが、「raise」に続けて例外クラス名だけを書くと、引数なしで「例外クラス名()」呼び出しが行われる)。

class MyStack:
    def __init__(self):
        self.stack = []
    def push(self, item):
        self.stack.append(item)
    def pop(self):
        if len(self.stack) == 0:
            raise EmptyStackError
        return self.stack.pop()

変更後のEmptyStackErrorクラスを利用するコード例

 実行結果は省略する。

まとめ

 今回は自分が書くコードから例外を送出する方法と、Pythonが標準で提供している例外クラスの概要、独自の例外クラスを定義する方法を見た。次回はファイル操作について見ていくことにしよう。

今回のまとめ:

  • 例外を送出するにはraise文を使用する
  • このときには「raise」に続けて、例外クラスのインスタンスか、例外クラス名を与える
  • 例外クラスのインスタンスの生成時には、例外処理を行う側に役立つメッセージや情報を含めることができる
  • 例外処理を行う側では、それらの情報をインスタンス変数のargsから取得できる
  • BaseExceptionクラスは全ての例外クラスの基底クラスとなる
  • Exceptionクラスは多くの組み込み例外クラスの基底クラスとなる
  • 独自に例外クラスを定義するときにはExceptionクラス(またはその派生クラス)を継承するクラスとする

前のページへ 1|2       

Copyright© Digital Advantage Corp. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。