何かがうまくいかないとき
Python が頼まれたことをできないとき、例外を送出します。float("abc") は ValueError、{}["x"] は KeyError、1 / 0 は ZeroDivisionError、存在しないファイルを開くと FileNotFoundError です。何も処理しなければプログラムは止まり、そこに至った呼び出しの連なりであるトレースバックが表示されます(下から上へ読みます)。本物のバグならそれが正しい結果です。ユーザーが入力した不正な価格のような予想できる問題は、try と except で処理します。
# Handle an expected problem
def to_price(text):
try:
return float(text)
except ValueError:
return None
print(to_price("184.25")) # 184.25
print(to_price("abc")) # None
# An unhandled one stops the program with a traceback
# print(int("abc")) # ValueError: invalid literal for int()...想定するものだけ捕まえる
例外の型を指定します:except ValueError:。単なる except: や except Exception: は、None を渡したことによる TypeError のような隠すつもりのなかったバグまで飲み込み、プログラムは誤ったデータで進んでしまいます。複数の型は except (ValueError, KeyError): のように1つのハンドラーで扱うことも、別々に書くこともできます。Python はハンドラーを順に試し、最初に一致したものを実行します。except ValueError as error: でエラーを受け取って調べることもできます。
# Specific handlers, tried in order
def read_quantity(text):
try:
return int(text)
except ValueError as error:
print("not a whole number:", error)
return 0
except TypeError:
print("expected text, got something else")
return 0
print(read_quantity("200")) # 200
print(read_quantity("2.5")) # prints the message, then 0
print(read_quantity(None)) # prints the message, then 0else と finally
文を完成させる省略可能な2つの部分があります。else: は try ブロックで何も送出されなかったときだけ実行され、危険な行を短く保ち、後続のコードを保護の外に置けます。finally: はエラーの有無にかかわらず、return の後でも必ず実行され、後片付けに使います。ファイルのように、with ブロックがすでに後片付けをしてくれることも多くあります。
# else runs on success, finally runs always
def describe(text):
try:
price = float(text)
except ValueError:
print("bad price")
else:
print("price is", price)
finally:
print("done with", repr(text))
describe("184.25")
# price is 184.25
# done with '184.25'
describe("abc")
# bad price
# done with 'abc'自分で例外を送出する
受け付けられない値を渡された関数は、黙って誤った値を返すのではなく、raise ではっきり拒否すべきです:raise ValueError("price must be positive")。適切な組み込みの型(型は正しいが値が悪いなら ValueError、型が違うなら TypeError)を選び、何が悪かったかを伝えるメッセージを書きます。捕まえるかどうかは呼び出し側が決めます。except ブロックの中での単独の raise は、捕まえたばかりのエラーを再送出するので、記録だけしたいときに便利です。
# Refuse bad input, let the caller decide
def parse_price(text):
price = float(text) # may raise ValueError itself
if not price > 0:
raise ValueError("price must be positive")
return price
for text in ["184.25", "-5", "abc"]:
try:
print(parse_price(text))
except ValueError as error:
print("rejected:", error)
# 184.25
# rejected: price must be positive
# rejected: could not convert string to float: 'abc'except(except: pass)は、デバッグできたはずのクラッシュを、静かに誤った数値へと変えてしまい、トレードのコードでははるかに危険です。エラーは、既定値を使う、その項目を飛ばす、再試行する、報告して止めるなど、妥当な対応がわかる場所でだけ捕まえましょう。そうでなければ、対応を知っている場所まで伝播させます。try/except SpecificError:想定する問題だけを処理するelseは何も送出されなかったとき、finallyは必ず実行されるraise ValueError("message")で不正な入力をはっきり拒否する
次はモジュールとインポートです。標準ライブラリや自分のファイルのコードを再利用する方法を学びます。
ラボ:採点される内容
safe_floatでクラッシュせずにテキストを変換する25点parse_priceで不正な価格を拒否する25点first_valid_priceで不正な項目を飛ばす25点read_quantityでファイルの欠落や破損に対処する25点