今回のお題
今回は、pythonのtry構文についてまとめます。
例によって、自分用のメモです。
目次
- try構文とは
- raise文
- 複数の例外への対応
- 全ての例外への対応(机上論編)
- Exceptionクラス
- as, from
try構文とは
try構文とは、例外(いわゆるエラー)が発生した場合の処理を決めるための構文です。
例外処理とはコンピュータが想定していない処理、すなわち0で割り算をしたりstrオブジェクト用のメソッドをintオブジェクトに使ったりといったことですね。
通常は例外処理が行われるとエラーになってプログラムが停止しますが、try構文を用いることで「このエラーの時にはプログラムを止める代わりにこの処理を実行してね」と個別の指示を出すことができます。
以下がtry構文の例です。
try:
print(1 / 0)
except ZeroDevisionError:
print("0で割らないでください")
上記のtest.pyを実行すると、まずtry以下の処理が呼び出されます(今回はprint(1 / 0))。
もしエラーが発生した場合、そのエラーの型がexcept以下のもの(今回はZeroDevisionError)であれば通常のエラー表示ではなく特別な処理(今回であればprint("0で割らないでください"))を実行します。
今回は省略しますが、exceptの後にelseやfinallyを用いることでエラーがなかった場合の処理やエラーの有無に関わらず共通して行う処理をそれぞれ指定することができる。
raise
エラーの型とメッセージを指定して意図的にエラーを発生させることのできる構文です。
あるエラーが発生した際に他のエラー名を表示したい場合などに使います。
try:
print(1 / 0)
except ZeroDevisionError:
raise TypeError("エラーです")# 型は"raise エラーの型(メッセージ)"
上記の例ではZeroDevisionError発生時には"TypeError:エラーです"と表示されるように設定しています。
複数の例外への対応
先程の例ではZeroDevisionErrorを想定し、それに対する例外処理を用意しました。
しかし、それ以外のエラーが発生した場合にはプログラムが止まってしまいます。
そこで複数のエラーが想定される場合には、exceptを複数用意することで対応します。
def devide(a, b):
try:
print(a / b)
except ZeroDevisionError:
print("0で割らないでください")
except TypeError:
print("文字ではなく数字を入力してください")
上記の例ではb = 0の場合には"0で割らないでください"、aかbに数字以外のものが代入された場合には"文字ではなく数字を入力してください"と出力されるようにしています。
また、複数のエラーに対して同じ処理を実行する場合にはexcept以下にエラーの型をタプルの形で記述することで処理をまとめることが可能です。
def devide(a, b):
try:
print(a / b)
except(ZeroDevisionError, TypeError):
print("エラーが発生しました")
全てのエラーへの対応(机上論編)
想定されるエラーが複数ある場合には、一つ一つ型を記述するのは大変です。
そこでそのような場合にはexcept以下のエラーの型を省略する、もしくは全てのエラーの親クラスであるBaseExcepitonクラスを指定すると全てのエラーに対する例外処理とすることができます。
# 省略パターン
def devide(a, b):
try:
print(a / b)
except:
print("エラーです")
# BaseExceptionパターン
def devide(a, b):
try:
print(a / b)
except BaseException:
print("エラーです")
これでどのようなエラーが出ても"エラーです"と出力されるようになりました。
ただ、逆を言えばどんなに致命的なエラーが発生してもプログラムが停止しないようになってしまうというデメリットがあります。
なので実際にはこのBaseExceptionクラスではなく次に紹介するExceptionクラスを使用することが推奨されています。
Exceptionクラスとは
Exceptionクラスは、全ての親であるBaseExceptionから見れば子供、これまでに出てきたZeroDevisionErrorやTypeErrorから見れば親にあたります。
ただしBaseExceptionとは異なり、SystemExitなどのシステム終了を伴うような重大なエラーの親にはあたらない(位置的には兄弟)なので、BaseExceptionに比べれば比較的低リスクで広範囲のエラーに対応できます。
as
asは発生したエラーを変数に格納して例外処理の中で参照する場合に用います。
変数名はなんでも構いませんが、eやerrが一般的です。
try:
print(1 / 0)
except ZeroDevisionError as e:
print(e)
# 出力:devision by zero
上記の例では、ZeroDevisionErrorを変数eに格納して出力しています。
eには基本的にエラーに対応したメッセージが代入されます。
また、エラーの元となった処理の引数を例外処理の中で用いることもできます。
# 引数一つ
def return_half(a):
try:
print(a / 2)
except TypeError as e:
raise TypeError("%s is not a number" % a) from e
# 引数二つ以上
def divide(a, b):
try:
print(a / b)
except BaseError as e:
raise TypeError("%s can't be divided by %s" % (a, b)) from b
上記の例ではエラーメッセージの中に関数の引数を入れています。
2つ目の例のように引数が二つ以上になる場合にはタプルの形を取ります。
また、メッセージの中身ですが、
("%s ...省略... " % a)
と記述することでaが%sの部分に代入されると考えてください。
終わりに
以上がtry構文の簡単な使い方でした。
この記事を書こうと思い立ったきっかけは、djangoの認証周りのファイルを見ていてtry文が大量発生していたことです。
そちらについての記事も近々上げる予定なので、よろしければご覧ください。