Yamamoto's Laboratory
 
環境設定
 
プログラム作成
  書き方
 
例外
 
 
 
tkinter
 
 
 
 
 
 

Python例外 (try — exept)

Python の例外 (try — except) の使い方を説明します.この構文を使うと,プログラムの例外処理 (実行時エラー) を簡単に分かりやすく記述することができます.Python っぽいプログラムを書くためには,ぜひ見つけて欲しい知識です.

目次


はじめに

例外とは

プログラムには二種類のエラーがあります.ひとつは文法上のエラーで,シンタックスエラーあるいは構文エラーと呼ばれるもので,定められた構文規則 (文法) を満たしていない時に発生します.通常,これは実行に先立ってチェックされます.もう一方は,実行時エラーです.文法は正しいのですが,実行するとおかしな挙動が起きます.例えば,数値をゼロで割るようなエラーがあります.この実行時のエラーを Python では例外 (exception) と呼びます.

要するに,例外は「プログラムの文法は正しいが,正しく動作しないエラー」です.他のプログラミング言語では実行時エラーと呼ばれるものです.

例外処理が必要な理由

多くの例外は,プログラムを使うユーザーの不注意で発生します.これは度々発生するため,プログラマーは「ユーザーが誤った使い方をしてもきちんと動作する」ようにプログラムを作成しなくてはなりません.そのためには,プログラマーが意図していない動作をユーザーが行った場合など,その対策の処理を書きます.Python には例外処理のための構文 (try &mdahs; except) が用意されています.

例外処理を記述することで,プログラムはロバスト (堅牢) になります.

他の言語との比較

実行時エラーが起きた場合の処理はプログラミング言語 (あるいはコンパイラー) によって異なります.多くの言語は戻り値で実行時エラーの内容を知らせます.そして,自動的に停止する言語も多いです.実際のプログラムでは,戻り値に応じた処理を記述します.この処理をあちこちに書くことになり,かなりの労力が必要です.これって,かなり大変です.Python には,この実行時エラーを処理する構文 (try — except) があります.この構文を使うことで,プログラムは分かりやすくなります.

以下の例は,実行時エラー (ゼロ割) の処理を記述した Python と C言語のプログラムです.

a = 0
try:
    b = 123/a
    print(b)
except ZeroDivisionError as err:
    print('error: ', err)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(){
  double a, b;
  a = 0;
  b = 123/a;
  if(b == INFINITY){
    printf("error: division by zero\n");
    exit(0);
  }
  else{
    printf("%.3e\n", b);
  }
    
  return 0;
}

この二つのプログラムは全く同一の結果になります.いずれも実行すると,コンソールに「error: division by zero」と表示されます.Python のプログラムの方が,短くて分かりやすいです.実際のプログラムでは,結構多くの例外処理が必要です.そのため,短くて分かりやすいということはとても大事です.

この Python のプログラムは,次のように動作します,

  1. 変数 a に 0 が代入されます(正確には違う).
  2. b=123/a を実行します.a=0 なのでゼロ割の例外が発生します.例外が発生したので,次行の「print(b)」は実行されません.
  3. 「except ZeroDivisionError as err」で例外をキャッチし,例外のオブジェクトを err へ代入します.
  4. オブジェクトの err を表示します.通常,エラーの内容が現れます.

書き方と動作の基本

基本

例外処理の「try — exept」の書き方を説明します.一般的な書き方は,以下のとおりです.try があるとひとつ以上の except が必要です.else や finally は無くても問題なく実行できます.

try:
トライで実行する処理を書きます (try 節)

except 例外名 as 変数:
例外名で指定された例外の処理を書きます (except 節)

except:
これまでにキャッチされていない例外の処理を書きます (except 節)

else:
例外が発生しなかった場合の処理を書きます (else 節)

finally:
例外の有無にかかわら実行される処理を書きます (finally 節)

このようにプログラムを書くと,try 節が実行されます.そこで例外の発生の有無によって動作が異なります.具体的には:

例外発生有りの場合
try 節を実行します.ここで例外が発生したら,この節の例外発生以降の行の命令は実行されません.発生と同時に,例外をキャッチする except を探します.探す順序は上から下にです.例外にマッチする except が見つかれば,その節を実行します.実行される except 節は最初に見つかったひとつだけです.そして,finally 節があれば,それを実行します.
例外発生無しの場合
try 節を最後まで実行します.そして,else 節を実行します.最後に,finally 節を実行します.

です.注意すべきことは,(1) try 節で例外が発生したらその節の以降の行の命令は実行されない,(2) except 節は最初に例外にマッチしたもののみ実行される,ことです.あとはプログラムを見ての想像のとおりです.

例外に関わるコマンドの書き方は,以下のとおりです.

ブロック書式 内容
except 例外名: 指定された例外が発生した時に処理する.
except 例外名 as 変数名: 変数名には例外の情報のオブエクとが代入される.
except (例外名A, 例外名B): 複数の例外に対応した処理をする.
except (例外名A, 例外名B) as 変数名: 複数の例外.変数名には例外の情報のオブジェクトが代入.
except: 全ての例外に対応した処理をする.
else: 例外が発生しなかった場合の処理をする.
finally: 例外が発生した場合も,しなかった場合も処理をする.

例外の送出 (raise)

例外を送出 (raise) には,二通りの方法 (自動送出,明示的送出) があります.自動送出では,Python に組み込まれた関数 (メソッド) で例外が発生すると自動的に搬出します.ユーザーはそれをキャッチする except 節を書くだけです.明示的に送出するには,ユーザープログラムで例外を送出するコマンド「raise 例外名」を記載します.例外名には予め用意されている組み込み例外とユーザーが作成するカスタム例外の二通りがあります.

ここでは,三個の具体的なプログラムを用いて例外の送出の方法を示します.いずれのプログラムの動作は,全く同一で,1行毎にファイルの内容を読み込んで表示します.ファイルが無かった場合,例外を送出します.そして,except 節で例外をキャッチし,エラーメッセージを表示し,プログラムを終了します.

自動送出

Python の組み込み関数 (メソッド) は自動的に組み込み例外を送出する機能を持っているものがあります.関数の例外送出は,マニュアルに記載があります.例外の自動送出の機能がある場合は,ユーザーが明示的に例外の送出 (raise) を記述する必要はありません.以下のプログラムでは,例外があると自動的に組み込み例外: OSError が送出されます.

try:
    file_path = input('ファイル名: ')
    with open(file_path, 'r') as f:
        for line in f:
            print(line, end='')
except OSError as err:
    print(err)

組み込み例外を明示的に送出

コマンド raise を使うと明示的に例外を送出することができます.以下の例は,組み込み例外を送出 (raise) するプログラムです.ファイルの有無をチェックして,ファイルが無い場合は組み込み例外: ValueError を送出します.

import os.path

try:
    file_path = input('ファイル名: ')
    ret = os.path.isfile(file_path)
    if not ret:
        raise ValueError('ファイルがありません') # 組み込み例外送出
except ValueError as err:
    print(err)
else:
    with open(file_path, 'r') as f:
        for line in f:
            print(line, end='')

組み込みの例外を送出のコマンドは raise ValueError('ファイルがありません') です.この raise で組み込み例外「ValueError」を送出します.その例外は except ValueError as err: でキャッチされます.

カスタム例外の作成と送出

次は,ユーザーが作成したカスタム例外の例です.カスタム例外と言っても難しくはありません.メンバー関数 (メソッド) に,__init__ と __str__ を記述するだけです.

import os.path

class CustomException(Exception):   ### カスタム例外の定義のクラス
    ''' カスタム例外です '''
    def __init__(self, value):
        self.parameter = value

    def __str__(self):
        return repr(self.parameter)

class PrintFile():
    ''' ファイルを読んでディスプレイに出力します '''
    def __init__(self, file):
        self.file_path = file

    def out_display(self):
        if not os.path.isfile(self.file_path):
            raise CustomException('ファイルがありません')  ### カスタム例外送出
        with open(self.file_path, 'r') as f:
            for line in f:
                print(line, end='')
            
if __name__ == '__main__':
    try:
        file_path = input('ファイル名: ')
        PrtFl = PrintFile(file_path)
        PrtFl.out_display()
    except CustomException as err:
        print(err)
    else:
        del PrtFl

このプログラムのクラス「CustomException(Exception)」がカスタム例外です.カスタム例外の書き方の基本は以下のとおりです.

  • クラス「Exception」を継承します.
  • コンストラクター __init__ を書きます.
  • オブジェクトの文字列表現の __str__ を書きます.戻り値には repr() を使います.

カスタム例外のクラスを作成したら,使い方は組み込み例外と全く同じです.

例外のキャッチ (except) の順番

例外のクラス (オブジェクト) に親子関係がある場合には注意が必要です.子のオブジェクトが例外を送出した場合,親のクラス名も例外としてキャッチされます.具体的には,以下のカスタムの例外のプログラムで説明します.

[注意] 以下のカスタム例外 (A, B, C) は __init__ も __str__ も無い,最も単純な例です.例外の名前があるだけですが,きちんと動作します.

class A(Exception):  # Exception を継承
    pass

class B(A):          # Exception > A を継承
    pass

class C(B):          # Exception > A > B を継承
    pass

for test_class in [A(), B(), C()]:
    try:
        raise test_class
    except C:
        print('C', end='')
    except B:
        print('B', end='')
    except A:
        print('A', end='')

このプログラムを実行すると「ABC」と表示されます.もし「except A:」を最初に記述すると,実行結果は「AAA」となります.この動作は,親のクラス名も例外として送出されることと,最初にキャッチした例外のみが実行されることを考えると,理解できます.

以上の例で分かるように,例外処理を記述する場合,except 節の順番が重要です.子プロセスから親プロセスの順番に記述しなくてはなりません.誤って親プロセスの例外を先に記述すると,子プロセスの例外が実行されることはありません.組み込み例外の親子関係 (階層) は「組み込み例外」に示します.

全ての例外をキャッチする「except:」はプログラムに最後に記述します.途中に記述すると,それ以降の except 節は実行されることが無いからです.

プログラム例

組み込み例外

キー入力のチェック

整数のキー入力を要求するプログラムです.整数以外の入力があると,例外が発生します.

while True:
    try:
        x = int(input("Please enter a number: "))
    except ValueError as err:
        print(err)
        print("入力は整数だよ.もう一度")
    else:
        print(x)
        break

カスタム (ユーザー作成) 例外

なにか良い例を思いついたら追記します.

組み込み例外 (階層と内容)

以下に,組み込み例外の階層 (ツリー) を示します. をクリックするとツリーを開くことができ, をクリックするとツリーを折りたたみます.ます.例外の説明は,Python のドキュメント「組み込み例外」から引用 (コピー) しました.

ページ作成情報

参考資料

更新履歴

2021年09月19日 ページの新規作成


no counter