Pythonで例外メッセージを正しく取得する方法


103

Pythonの標準ライブラリのコンポーネントから例外のメッセージを取得するための最良の方法は何ですか?

場合によっては、次のmessageようなフィールドから取得できることに気付きました。

try:
  pass
except Exception as ex:
  print(ex.message)

ただし、場合によっては(たとえば、ソケットエラーの場合)、次のようなことを行う必要があります。

try:
  pass
except socket.error as ex:
  print(ex)

これらの状況のほとんどをカバーする標準的な方法はありますか?


1
あなたは2つの異なることを混同しています-エラーが属性に伴うかどうかは別ですexcept Foo as bar:が、except Foo, bar:(前者がより新しく、3.xで引き続き機能することを除いて)同じmessageです。
jonrsharpe 2015年

1
@FrozenHeart.messageエラーへのアクセスが標準的な方法であるかどうかを尋ねていますか?
Anand S Kumar

の2番目の例print(msg)は、次のショートカットですprint(str(msg))
Salo

@アナンドSクマールうん。とにかく動作しますか?
FrozenHeart 2015年

5
アクセスmessageは非推奨になると思います。
Jonathon Reinhart

回答:


101

組み込みエラードキュメントを見ると、ほとんどのExceptionクラスが最初の引数をmessage属性として割り当てていることがわかります。しかし、それらすべてがそうするわけではありません。

特に、EnvironmentError(サブクラスIOErrorOSError)の最初の引数はerrno、の2番目ですstrerror。ありませんmessage...strerror通常のように大まかに類似していmessageます。

より一般的には、のサブクラスExceptionは好きなことを行うことができます。それらにはmessage属性がある場合とない場合があります。将来の組み込みExceptionmessage属性を持たない可能性があります。任意のExceptionサードパーティ製のライブラリまたはユーザーコードからインポートサブクラスは持っていない可能性がありmessage、属性を。

これを処理する適切な方法はException、キャッチしたい特定のサブクラスを識別し、すべてではなくそれらだけをキャッチし、except Exception特定のサブクラスが定義する属性を任意に利用することだと思います。

あなたがprint何かをしなければならないなら、私Exceptionはそれがmessage属性を持っているかどうかにかかわらず、捕らえられたもの自体を印刷することはあなたが望むことをする可能性が最も高いと思います。

このように、必要に応じてメッセージ属性を確認することもできますが、面倒に見えるため、実際にはお勧めしません。

try:
    pass
except Exception as e:
    # Just print(e) is cleaner and more likely what you want,
    # but if you insist on printing message specifically whenever possible...
    if hasattr(e, 'message'):
        print(e.message)
    else:
        print(e)

答えてくれてありがとう。str(ex)だけでなく使用する特別な理由はありますexか?
FrozenHeart 2015年

4
@ FrozenHeart-print()自動的str()にあなたを呼び出します。手動で呼び出す理由はありませんstr()が、文字列を呼び出すと文字列自体が返されるだけなので無害です。
ArtOfWarfare 2015年

1
@ArtOfWarfarestr()メッセージがタイプの場合、問題が発生する可能性があると思いますunicode
kratenko 2015年

39

@artofwarfareによって提供された回答を改善するために、message属性をチェックして印刷するかException、フォールバックとしてオブジェクトを印刷するためのより適切な方法と私が考えるものを次に示します。

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))

toの呼び出しreprはオプションですが、ユースケースによっては必要だと思います。


更新#1:

@MadPhysicistによるコメントに続いて、への呼び出しreprが必要になる理由の証拠がここにあります。インタプリタで次のコードを実行してみてください。

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))

アップデート#2:

Python 2.7および3.5の詳細を含むデモを次に示しますhttps//gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533


1
getattr渡されたオブジェクトに要求された属性がない場合、例外をスローします。あなたがそのような何かをしたい場合、私はあなたのために、オプションの三番目の引数を使うべきだと思うgetattr。このように、: print getattr(e, 'message', e)。私がやったことよりも間違いなく良い。別のオプションはですprint(e.message if hasattr(e, 'message') else e)
ArtOfWarfare 2017

2
str代わりに、ほぼ確実に必要になりreprます。
狂牛病の物理学者

2
と比較してstrreprクラス名を追加するだけです。を使用する代わりに、を使用reprすることを提案しますprint('{e.__class__.__name__}: {e}'.format(e=e))。印刷出力はよりクリーンで、レイズ自体の出力に準拠しています。
ケーディー

1
以上を踏まえ、私は私がするために最も有用であることが判明'{e.__class__.__module__}.{e.__class__.__name__}: {e}'
シャディ・

1
ありがとう!repr(e)今のところ、特定の状況で発生したエラーについて、少なくとも最小限の情報を印刷するのに役立つ唯一の解決策でした。repr(e)KeyError(0,)(エラーが何であるか)を生成しますが、str(e)またはe.message0それぞれ生成するか、まったく生成しません。
FlorianH

0

私も同じ問題を抱えていました。最善の解決策は、log.exceptionを使用することだと思います。これにより、次のようなスタックトレースとエラーメッセージが自動的に出力されます。

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')

2
logですか?import logPython 2.7.13を試してみたところ、その名前のモジュールがないというメッセージが表示されました。それはあなたが経由して追加したものですpipか、それとも新しいバージョンのpythonで追加されたものですか(私は知っています、私は知っています、私はPython3に更新する必要があります... CentOSがデフォルトでPython2で出荷を停止するとすぐにそれを行います...)
ArtOfWarfare19年

7
彼/彼女はおそらくPythonのロギングモジュールを使用していて、ログ変数としてロガーをインスタンス化しています。import logging\ nはlog = logging.getLogger(__name__)
Josepas

0

私も同じ問題を抱えていました。これを掘り下げてみると、Exceptionクラスにはargs、例外の作成に使用された引数をキャプチャする属性があることがわかりました。例外がキャッチする例外をサブセットに絞り込むと、それらがどのように構築されたか、したがってどの引数にメッセージが含まれているかを判別できるはずです。

try:
   # do something that may raise an AuthException
except AuthException as ex:
   if ex.args[0] == "Authentication Timeout.":
      # handle timeout
   else:
      # generic handling
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.