Blog Entry  (Dec. 9, 2018, 8:56 a.m.)

Tilo Mitra's avatar

Pythonでエラー箇所を上書きしてしまわないようにする

Pythonで例外がが発生しそうな箇所で try して例外をキャッチし、ログを追加するなどビジネスロジックとは別の処理をしたあとに再び同じ例外を発生させたいときがあります。

このとき、 raise e のようにキャッチした例外をそのまま指定するコードを見かけますが、多くのケースでこれはあまり好ましくなく、何も指定しない raise とだけ書くことが好ましいです。

raise だけで同じ例外を発生させる事ができる

「Python文法詳解」には次のように書かれています。

except 節や、 finally 節で例外ハンドラの実行中には、例外オブジェクトを指定せずに raise 文を実行できます。この場合、例外中の例外オブジェクトが、自動的に再送出されます。 1

raise e raise は微妙に違う

raise e raise は似ている動作ですが、前者はエラーを追うときに苦労してしまいます。なぜなら、 except 内で raise e としてしまうと、一度例外をキャッチした上で新たに例外を発生させることになってしまうのでスタックトレースのエラー箇所は raise e と書いたところになってしまうからです。一方で raise だけならキャッチした例外を引き継ぎ、スタックトレースを汚しません。

def test1():
    try:
        raise StandardError()
    except Exception as e:
        raise e
def test2():
    try:
        raise StandardError()
    except Exception as e:
        raise

上記の2つのコードを実行してみます。結果は次のとおりです。

>>> test1()

# Traceback (most recent call last):
#   File "<input>", line 1, in <module>
#     test1()
#   File "<input>", line 5, in test1
#     raise e
# StandardError
>>> test2()

# Traceback (most recent call last):
#   File "<input>", line 1, in <module>
#     test2()
#   File "<input>", line 3, in test2
#     raise StandardError()
# StandardError

test1() は例外をキャッチした上で"新たに"例外 e を発生させているため5行目でエラーになったかのように見えます。一方で test2() raise で何も指定しておらず、3行目の実際のエラー箇所がスタックトレースに残っています。


  1. 石本敦夫 「Python文法詳解」 オライリー・ジャパン 2014年 p.184

元の記事へ