assert
デバックを作業を容易に行うため に使用されます
条件式がFalse
の場合にはAssertionError
を発生させて停止。
True
の場合はそのまま処理が続きます
assert "条件式をここに書く", "Falseの場合のメッセージ"
# 例)
# 1. AssertionErrorは発生せずに、処理は続く
assert "apple" == "apple", "りんごでは無いです"
# 2
assert "apple" == "orange", "りんごでは無いです"
# => AssertionError : りんごでは無いです
では、if文と、assert文の違いは?
同じ様に条件分岐をするif分との違いは何なのか
if "apple" == "apple":
is_same_fruit = True
else:
is_same_fruit = False
if文はTrue
でもFalse
でも条件によって処理を行うのに対し、
assert文はTrue
の場合は処理を行うが、False
の場合は AsserttionError
を発生させます
except
exceptは、例外処理を受け取ります。 また、キャッチするとも言います
想定外の処理が起きた時用の処理を用意します
try文
と一緒に使用します
try:
エラーが発生する可能性がある処理
except:
例外発生時の処理
こんな使い方がある
①未定義の変数の例外をキャッチする
未定義の変数は組み込み例外クラスのNameError
が発生します
try:
print(apple)
except ValueError as e:
print("ValueError をキャッチ")
print(e)
except NameError as e:
print(("NameErrorをキャッチ"))
print(e)
# => NameErrorをキャッチ
# => name 'apple' is not defined
try
にエラーが発生する可能性がある処理を書いています
仮にエラーが発生した場合、except
で例外をキャッチ出来るようになっています
上記の例では、未定義の変数が参照されようとしたので例外クラスであるNameError
が発生し、except NameError as e:
でキャッチしています
仮に、try/except
を書かない場合
print(apple)
# => print(apple)
# NameError: name 'apple' is not defined
キャッチするのではなく、例外であるNameError
が発生して処理が終了します
hogehoge:「そもそも、なぜ例外処理をキャッチする意味がある?」
hogehoge:「エラーとして、スタックトレースに出力されるんなら同じ事では?」
理由については後ほど記載。
② 例外オブジェクトを取得する
①のサンプルコードにもありましたが、
except 例外クラス as 変数:
とすることで、例外オブジェクトを取得することが出来ます
try:
print(apple)
except NameError as e:
print(e)
print(type(e))
except:
print("それ以外の例外")
# => name 'apple' is not defined
# => <class 'NameError'>
except
における疑問の解消
hogehoge:「そもそも、なぜ例外処理を発生させる意味がある?」
hogehoge:「エラーとして、スタックトレースに出力されるんなら同じ事では?」
-
該当の処理だけを止めるため
- 例外が起きると、処理が止まるが全体の処理が止まるわけではなく、例外の該当の箇所だけで収まる。
-
エラー原因の解析のため
- エラーが発生する可能性のある箇所で、意図的に例外としてキャッチすることで、解析しやすいようにエラーメッセージを添えることが出来る
-
ソフトランディングさせるため
- その後の処理で誤ったデータが登録されないように
- DBをロールバックさせるため
hogehoge:「
if else
でも代替えできるんじゃ?」
処理自体は可能。
だが、全てのエラーを予測して例外をキャッチしなければなりません
よって、try/except文
を使います
raise
例外を意図的に発生させたい場合に使用します
例外が発生する可能性のある箇所に書きます
raise
で例外を発生させて、except
でキャッチしたりします(後ほど、詳しく説明します)
raise 例外クラス(メッセージ)
# 例
raise RuntimeError("Something bad happened")
エラーが発生するとこんな感じでスタックトレースに出ます
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened
また、
- 独自で例外クラスを作る
- Exceptionクラスを継承したクラスを作る
なども可能です。
例えばこんな挙動になる
●<シンプルに、例外を発生させて、該当する例外をキャッチ>
raise NameError
で例外を発生させて、例外が検出された時、
該当の例外クラスのexcept
句が実行されます
try:
raise NameError("変数が定義されていません")
except NameError as e:
print(e)
# => 変数が定義されていません
●<例外を発生させて、該当する例外とは異なるのでキャッチ出来ない>
NameError
を発生させていますが、except
句ではValueError
を待っているのでキャッチ出来ません
except
句内の出力が確認できないことが分かります
しかし、例外はスタックトレースへエラーメッセージと共に送出されています
try:
raise NameError("変数が定義されていません")
except ValueError as e:
print(e)
print("例外をキャッチ!")
# Traceback (most recent call last):
# File "Main.py", line 5, in <module>
# raise NameError("変数が定義されていません")
# NameError: 変数が定義されていません
hogehoge:「結局のところ一番知りたいのは、exceptとraiseの違いは細かな違いって何?」
except と raiseの違い
公式にも記載があります
例外が発生したかどうかを判定したいだけで、その例外を処理するつもりがなければ、単純な形式の raise 文を使って例外を再送出させることができます
https://docs.python.org/ja/3/tutorial/errors.html#raising-exceptions
つまりどういうことかというと、
- 例外として、エラーメッセージを送出したいだけとかなら
raise
でOK -
例外が発生した後、処理を行いたい場合に
except
でキャッチする- エラーメッセージをdictへ整形したり、エラーログに残したり、csv出力したり とか
具体例を説明すると、
ここからは、コードをいくつか例を用いて説明します
(理解できている方は飛ばしてください)
●<raiseでエラーメッセージを送出したいだけ>
raise NameError("変数が定義されていません")
# Traceback (most recent call last):
# File "Main.py", line 1, in <module>
# raise NameError("変数が定義されていません")
# NameError: 変数が定義されていません
●<例外を発生させて、except句内で処理する>
Exception
クラスを継承している独自で作成したSampleException
を使って説明します。
条件分岐を行なって例外を発生させます
except句
では、SampleException
をキャッチして、except句
内の処理が行われます
class SampleException(Exception):
pass
def cal():
try:
a = 10
if a % 4 == 0:
raise SampleException("10は4で割り切れてしまいました")
elif a % 2 == 0: # 当条件に当てはまり例外が発生
raise SampleException("10は2で割り切れてしまいました")
elif a % 5 == 0:
raise SampleException("10は5で割り切れてしまいました")
except SampleException as e:
print(e)
print("例外キャッチ")
print("ここに処理を書く")
cal()
# 10は2で割り切れてしまいました
# 例外キャッチ
# ここに処理を書く
raise
を使用する場面とは?
- 致命的なエラーが発生する可能性のある時
- 自分が作った処理にエラーが発生した際に、それを外部に伝えるため
以下記事が、分かりやすいです
参考