Pythonの例外処理 "finally", "from" についてメモ
Python の例外処理の基礎的な部分を再確認した。
Python: 3.9.7 を使用。
finally がある場合の実行順序
もし
finally
節がある場合、try
文が終わる前の最後の処理を、finally
節が実行します。 8. エラーと例外 — Python 3.10.4 ドキュメント
def raise_error():
raise Exception(3)
try:
raise_error()
except Exception as e:
print(1)
raise e
finally:
print(2)
出力:
1
2
Traceback (most recent call last):
File "/Users/noy72/sandbox/python/error/finally.py", line 9, in <module>
raise e
File "/Users/noy72/sandbox/python/error/finally.py", line 6, in <module>
raise_error()
File "/Users/noy72/sandbox/python/error/finally.py", line 2, in raise_error
raise Exception(3)
Exception: 3
実行順序は以下のようになっている。
except
節のprint(1)
finally
節のprint(2)
except
節のraise e
finally
節が実行された後に例外(raise e
)再送されるので、↑の順で実行される。
finally
節の実行前に関数から抜けたらfinally
節の意味がないのでこの実行順序になるのは当たり前だけど、直感に反する感じがする。
raise ... from のエラーメッセージの変化
class SomeException(Exception):
pass
def raise_error():
raise Exception("エラーが発生しました")
try:
raise_error()
except Exception as e:
raise SomeException
上記のコードを実行した場合の実行結果は以下のようになる。Exception
をSomeException
で投げ直しているが、Exception
がどこで発生したかの情報も含まれている。
Traceback (most recent call last):
File "/Users/noy72/sandbox/python/error/raise_from.py", line 10, in <module>
raise_error()
File "/Users/noy72/sandbox/python/error/raise_from.py", line 6, in raise_error
raise Exception("エラーが発生しました")
Exception: エラーが発生しました
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/noy72/sandbox/python/error/raise_from.py", line 12, in <module>
raise SomeException
__main__.SomeException
当然だけど、raise SomeException(e)
にするとexcept
節で発生した例外のメッセージをSomeException
も持つことになる。
(略)
Traceback (most recent call last):
File "/Users/noy72/sandbox/python/error/raise_from.py", line 12, in <module>
raise SomeException(e)
__main__.SomeException: エラーが発生しました
raise SomeException from e
にすると、表示される文字列が変わる。
(略)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/noy72/sandbox/python/error/raise_from.py", line 12, in <module>
raise SomeException from e
__main__.SomeException
from
がない場合はDuring handling of the above exception, another exception occurred:
で、from
がある場合はThe above exception was the direct cause of the following exception:
となる。
例外の連鎖は、例外が
except
節またはfinally
節で送出された場合自動的に行われます。例外の連鎖を無効にするためにはfrom None
が利用できます:
from
があるときとないときでスタックトレースに変化がないのは例外の連鎖が有効なため。明示的にfrom
を使う場面があまりなさそうな気がする。
raise SomeException from None
と書いて実行すると以下のトレースが表示される。raise_error()
で発生したという情報がなくなる。
Traceback (most recent call last):
File "/Users/noy72/sandbox/python/error/raise_from.py", line 12, in <module>
raise SomeException from None
__main__.SomeException