Pythonでtry exceptの書き方と、エラー内容の取得方法

恥ずかしながら、今までPythonのプログラムを書いているとき、
ちゃんとエラー処理をしていませんでした。

というのも、exceptに何を記載したらよいのかいまいちわからないし、
エラーを受け取った時のエラーメッセージをどのように表示すればよいか
わからなかったので、スルーしてました。


最近、まれにエラーが発生するプログラムにエラー発生時のログを仕込みたい時に
とても困ったので調べたことをメモしておきます。



とりあえずtry-except



悪い例ですが、とにかくエラーが発生しても以降の処理を続行したい場合は、
try-exceptで囲ってしまえばOKです。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #エラーを発生させるため0除算
  6.     a = 10 / 0
  7.     print 'try-終了'
  8. except:
  9.     print 'エラー発生'
  10.     
  11. print '処理終了'





実行してみると、とりあえず最後までプログラムが実行されます。

処理開始
try-開始
エラー発生
処理終了








ちゃんとエラーオブジェクトを受け取る



厳密には、発生するであろうエラーに備えて、適切な例外クラスをexceptに
記載してやる必要があります。

6. 組み込み例外
http://www.python.jp/doc/release/library/exceptions.html

しかし、発生する例外を正しく予測しクラスを記述するのは至難の業ですし、
何がエラーになっているかわからないケースも多いかと思います。

Javaでいうと、こんな感じの処理にするため

  1. try {
  2.     hoge();
  3. } catch(Exception e) {
  4.     System.out.pritln("エラー発生");
  5. }



Exceptionクラスを指定してみました。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #エラーを発生させるため0除算
  6.     a = 10 / 0
  7.     print 'try-終了'
  8. except Exception as e:
  9.     print '=== エラー内容 ==='
  10.     print 'type:' + str(type(e))
  11.     print 'args:' + str(e.args)
  12.     print 'message:' + e.message
  13.     print 'e自身:' + str(e)
  14.     
  15. print '処理終了'




実行してみると、0除算でZeroDivisionErrorの例外が発生し、
integer division or modulo by zeroというエラーメッセージを
残してくれていることがわかります。

処理開始
try-開始
=== エラー内容 ===
type:<type 'exceptions.ZeroDivisionError'>
args:('integer division or modulo by zero',)
message:integer division or modulo by zero
e自身:integer division or modulo by zero
処理終了






もう一例、開こうとしたファイルが存在しないパターン。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #存在しないファイルをオープン
  6.     f = open('not_exist_file', 'r')
  7.     print 'try-終了'
  8. except Exception as e:
  9.     print '=== エラー内容 ==='
  10.     print 'type:' + str(type(e))
  11.     print 'args:' + str(e.args)
  12.     print 'message:' + e.message
  13.     print 'e自身:' + str(e)
  14.     
  15. print '処理終了'





IOErrorが発生し、No such file or directoryというメッセージを残してくれました。


処理開始
try-開始
=== エラー内容 ===
type:<type 'exceptions.IOError'>
args:(2, 'No such file or directory')
message:
e自身:[Errno 2] No such file or directory: 'not_exist_file'
処理終了









発生したエラーにより、処理を分岐する



とりあえず、0除算で「ZeroDivisionError」、ファイルを開くときに「IOError」が
発生することがわかったので、各々発生したエラーにより表示するメッセージを
変更してみます。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #エラーを発生させるため0除算
  6.     #f = open('not_exist_file', 'r')
  7.     a = 10 / 0
  8.     print 'try-終了'
  9. except ZeroDivisionError:
  10.     print '0で除算しましたね?'
  11.     
  12. except IOError:
  13.     print 'ファイルが存在しません。'
  14.     
  15. print '処理終了'




これで、try内で発生したエラーが0除算の場合は
「0で除算しましたね?」

開こうとしたファイルが存在しない場合は、
「ファイルが存在しません。」

というメッセージを表示することができました。



また、エラーを()でくくって列挙することで、ひとつのexceptで
複数のエラー処理を行うことができます。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #エラーを発生させるため0除算
  6.     #f = open('not_exist_file', 'r')
  7.     a = 10 / 0
  8.     print 'try-終了'
  9. except (ZeroDivisionError, IOError):
  10.     print '0で除算したか、ファイルが存在しません。'
  11.     
  12.     
  13. print '処理終了'



こうした場合、0除算かファイルのオープンエラーが発生した場合、
「0で除算したか、ファイルが存在しません。」
というメッセージが表示されました。



予期していない、文字列を数値に変換してエラーになった場合


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #エラー発生
  6.     a = int('string')
  7.     print 'try-終了'
  8. except (ZeroDivisionError, IOError):
  9.     print '0で除算したか、ファイルが存在しません。'
  10.     
  11. print '処理終了'




こんなかんじで、通常のスタックトレースが表示されます。

処理開始
try-開始
Traceback (most recent call last):
File "sample.py", line 10, in <module>
    a = int('string')
ValueError: invalid literal for int() with base 10: 'string'









elseとfinally



try-exceptには、elseとfinallyを記載することができます。

elseは、try内の処理が正常終了した場合に実行、
finallyは、try内の処理が正常終了、異常終了を問わず実行されます。

こんなコードを書いて試してみました。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #エラー発生
  6.     a = 10 / 0
  7.     
  8.     print 'try-終了'
  9. except (ZeroDivisionError, IOError):
  10.     print '0で除算したか、ファイルが存在しません。'
  11.     
  12. else:
  13.     print 'elseに来ました'
  14.     
  15. finally:
  16.     print 'finallyに来ました'
  17.     
  18. print '処理終了'





エラーが発生したので、elseは実行されず、finallyのみ実行されています。

処理開始
try-開始
0で除算したか、ファイルが存在しません。
finallyに来ました
処理終了





次に、エラーが発生しないパターン。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     print 'try-終了'
  6. except (ZeroDivisionError, IOError):
  7.     print '0で除算したか、ファイルが存在しません。'
  8.     
  9. else:
  10.     print 'elseに来ました'
  11.     
  12. finally:
  13.     print 'finallyに来ました'
  14.     
  15. print '処理終了'




else、finally共に実行されました。

処理開始
try-開始
try-終了
elseに来ました
finallyに来ました
処理終了






最後に予期していないエラーが発生した場合。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #予期していないエラー発生
  6.     a = int('string')
  7.     print 'try-終了'
  8. except (ZeroDivisionError, IOError):
  9.     print '0で除算したか、ファイルが存在しません。'
  10.     
  11. else:
  12.     print 'elseに来ました'
  13.     
  14. finally:
  15.     print 'finallyに来ました'
  16.     
  17. print '処理終了'




スタックトレースが表示されます。

処理開始
try-開始
finallyに来ました
Traceback (most recent call last):
File "sample.py", line 8, in <module>
    a = int('string')
ValueError: invalid literal for int() with base 10: 'string'










まとめ



こんなコードを書いて、なんのエラーが発生したかわからないままにするよりも、


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #エラー発生
  6.     a = int('string')
  7.     print 'try-終了'
  8. except:
  9.     print 'なんかのエラー'
  10. print '処理終了'





せめて、Exceptionを捉えて、内容をログに出力しておくぐらいはやったほうが、
バグが発生したとき幸せになれると思います。


  1. # -*- coding:utf-8 -*-
  2. print '処理開始'
  3. try:
  4.     print 'try-開始'
  5.     #エラー発生
  6.     a = int('string')
  7.     print 'try-終了'
  8. except Exception as e:
  9.     print e.message
  10.     
  11. print '処理終了'



関連記事

コメント

プロフィール

Author:symfo
blog形式だと探しにくいので、まとめサイト作成中です。
https://symfo.web.fc2.com/

PR

検索フォーム

月別アーカイブ