traceback の情報を残しつつ別の型の例外を送出
触発されて、例外の再送出について調べてみました。
例外を捕らえたものの処理しきらないで再送出する場合、 methane さんの指摘の通り、情報量の少ない自作例外にしてしまうのは最悪です。しかし、 raise e としても traceback 情報がなくなってしまうため、これでもダメです。こういうときにはただ raise と書きます。
しかし、 Language Reference によると自作例外など別の型の例外を送出しつつ、 traceback の情報を残すことも可能ということがわかりました。 Python 2 系では raise 文の 3 つめの値に traceback オブジェクトを渡します。 Python 3 系では raise 文の後ろに from 節をつけ、これに例外オブジェクトを添えます。
情報源
- http://www.python.jp/doc/2.5/ref/raise.html (Python 2.5 日本語訳)
- http://docs.python.org/reference/simple_stmts.html#raise (Python 2 系最新)
- http://docs.python.org/3.0/reference/simple_stmts.html#the-raise-statement (Python 3.0)
ただの raise で足りていて困ったことが無いため、この機能をどういう状況で使うべきなのかは不明ですが…。以下、 Python 2.5.2 on win32 での実験コードです。
import sys import traceback class MyZeroDivisionError(ZeroDivisionError): pass def zero(): return 1/0 def ng1(): try: zero() except ZeroDivisionError, e: raise MyZeroDivisionError('division by zero') def ng2(): try: zero() except ZeroDivisionError, e: raise e def reraise(): try: zero() except ZeroDivisionError, e: raise def ok(): try: zero() except ZeroDivisionError, e: t = sys.exc_info()[2] raise MyZeroDivisionError('division by zero'), None, t funcs = [ng1, ng2, reraise, ok] def main(): for func in funcs: print func.__name__ try: func() except: print traceback.format_exc() if __name__ == '__main__': main()
出力です。
ng1 Traceback (most recent call last): File "S:\Python\test_traceback.py", line 41, in main func() File "S:\Python\test_traceback.py", line 14, in ng1 raise MyZeroDivisionError('division by zero') MyZeroDivisionError: division by zero ng2 Traceback (most recent call last): File "S:\Python\test_traceback.py", line 41, in main func() File "S:\Python\test_traceback.py", line 20, in ng2 raise e ZeroDivisionError: integer division or modulo by zero reraise Traceback (most recent call last): File "S:\Python\test_traceback.py", line 41, in main func() File "S:\Python\test_traceback.py", line 24, in reraise zero() File "S:\Python\test_traceback.py", line 8, in zero return 1/0 ZeroDivisionError: integer division or modulo by zero ok Traceback (most recent call last): File "S:\Python\test_traceback.py", line 41, in main func() File "S:\Python\test_traceback.py", line 30, in ok zero() File "S:\Python\test_traceback.py", line 8, in zero return 1/0 MyZeroDivisionError: division by zero