ユーニックス総合研究所

  • home
  • archives
  • python-exception

Pythonの例外(exception)の投げ方

  • 作成日: 2021-02-09
  • 更新日: 2023-12-24
  • カテゴリ: Python

Pythonの例外(exception)の投げ方

🦝 < こんにちは、またお会いしましたね。

今回はPythonの例外(exception)についてご紹介させていただきます。
例外とはPythonのエラー処理に使われる機構です。

Pythonのエラー処理では一般的にこの例外がよく使われています。

この記事では例外について具体的に↓を見ていきます。

  • 例外とは?
  • raiseを使って例外を投げる
  • 例外の射程距離
  • raise fromで例外を継承する
  • Exceptionクラス
  • よく使う汎用例外

例外とは?

Pythonのエラーには少なくとも2つの種類があります。
1つが構文エラーで、もう1つが例外です。
つまり例外というのは、Pythonにおいてはエラーの一部分だということになります。

構文エラーと言うのはコードの文法的なエラーです。シンタックス・エラーとも呼ばれます。
ほら、タイポしたり勘違いしたりして、間違ったコードを書くことがよくありますよね。
そういう時にPythonインタプリタがかんしゃくを起こして「ここ間違ってるよ!」と教えてくれるのが構文エラーです。

いっぽう例外と言うのは、プログラムの実行中に起こるエラーのことです。
たとえばゼロで除算してしまったり、ファイルがなかったり、権限がなかったりといったときに発生します。
こういったエラーを総称してPythonでは例外といいます。

例外は構文が合っていても起こる可能性のあるエラーです。
Pythonがコードを実行していく中ではじめて遭遇するエラーがこの例外です。
逆に言うと、Pythonがコードを実行しなければ例外は起こることが無いということです。

プログラムのエラーと言うものは実行中にそのほとんどが起きます。
そのため、例外を扱うというのはPythonにおいてエラー処理を扱うというのとほとんど同義になります。
例外を知らなければエラー処理がわからず、エラー処理がわからなければうまくプログラムも作れない・・・・・・ということになりかねません。

この記事では例外の全ては扱いません。特にtry文については別の記事を参照してください。
この記事では例外の「投げ方」について焦点を当てています。

raiseを使って例外を投げる

それでは例外を投げる方法をご紹介します。
Pythonで例外を投げるにはraise(レイズ)というキーワードを使います。
このraiseの右側に投げたい例外オブジェクトを指定すると、その例外を投げることが出来るようになります。

raise 例外オブジェクト  

では実際に例外を投げてみましょう。
今回投げるのはExceptionクラスという基本的な例外オブジェクトです。
このExceptionクラスはPythonの組み込み例外で、インポートしなくても使うことが出来ます。

raise Exception('体力の限界です')  

↑のコードを実行すると↓のような結果になります。

Traceback (most recent call last):  
  File "./sample.py", line 1, in <module>  
    raise Exception('体力の限界です')  
Exception: 体力の限界です  

raiseを実行すると例外が送出されます。
そしてキャッチされない例外は↑のようにインタプリタにスタックトレースを吐かせます。

例外の射程距離

例外の特徴として、関数やスコープを飛び越えてエラーが伝わっていくという性質があります。
これはどういうことかと言うと、↓にわかりやすいサンプルコードをご用意しましたのでご覧ください。

def f():  
    print('ミカン美味しい')  
    raise Exception('体力の限界です')  
    print('リンゴ美味しい')  


f()  

↑のコードを実行すると↓のような結果になります。

ミカン美味しい  
Traceback (most recent call last):  
  File "./sample.py", line 7, in <module>  
    f()  
  File "./sample.py", line 3, in f  
    raise Exception('体力の限界です')  
Exception: 体力の限界です  

↑のコードでは関数fの中で例外を投げています。
その投げた例外は関数の中から飛び出てグローバルな領域までジャンプします。
そして例外はインタプリタの実行を中断させます。

「ミカン美味しい」というprint()が実行された後にraiseされているので、raiseのあとの「リンゴ美味しい」というprint()は実行されません。
これはraiseが実行された段階でプログラムの処理が関数から飛び出たということの表れなんですね。

このように例外は関数やメソッドなどのスコープをジャンプします。
これは関数が何重になっていても同じことです。

raise fromで例外を継承する

例外と言うのはtry文でキャッチすることが出来ます。
そしてキャッチした例外は継承して再raiseすることが可能です。
これはどういうことかと言うと↓のコードをご覧ください。

try:  
    raise Exception('猫が歩いた')  
except Exception as e:  
    raise Exception('犬も歩いた') from e  

↑のコードを実行すると↓のような結果になります。

Traceback (most recent call last):  
  File "./sample.py", line 2, in <module>  
    raise Exception('猫が歩いた')  
Exception: 猫が歩いた  

The above exception was the direct cause of the following exception:  

Traceback (most recent call last):  
  File "./sample.py", line 4, in <module>  
    raise Exception('犬も歩いた') from e  
Exception: 犬も歩いた  

↑のコードを見るとわかりますが、↓のようにすると例外は継承することが可能です。

raise 例外オブジェクト from 継承する例外オブジェクト  

↑の出力を見ると「猫が歩いた」という例外と「犬も歩いた」という例外が両方出力されているのがわかります。
これは「犬も歩いた」という例外オブジェクトが「猫が歩いた」という例外を継承しているためです。
エラーを連続して伝えるときに便利な仕組みです。

Exceptionクラス

例外を扱う時によくお世話になるのが組み込み例外であるExceptionクラスです。
Pythonでは新しい例外を作成するときはExceptionクラスかその派生例外クラスを継承することを推奨しています。

独自例外を作りたい場合は↓のようにExceptionクラスを継承したクラスを作ります。

class MyError(Exception):  
    pass  

Exceptionクラスを継承した汎用例外もいくつかありますのでよく使われるものをご紹介します……。

よく使う汎用例外

よく使われる汎用例外を3つご紹介します。
この他にも汎用例外は存在することにご注意ください。

ValueError

オブジェクトの値が不正だった時に送出する例外です。

raise ValueError('値が不正です')  

TypeError

オブジェクトのタイプが不正だった時に送出する例外です。

raise TypeError('不正なタイプです')  

OSError

ファイル入出力全般で送出される例外です。

raise OSError('ファイルが見つかりません')  

また、↑の「ファイルが見つかりません」という場合の例外はよりふさわしいものにFileNotFoundErrorという例外がございます。

おわりに

今回はPythonの例外(exception)について見て見ましたが、いかがでしたでしょうか。
例外を投げるということについては、もうこの記事をご覧いただけばばっちりかと思います……。

🦝 < それでは、またお会いできることを楽しみにしております。御機嫌よう……