コース進捗 コース目次 24レッスン中 24件を公開中
Pythonの基礎
データとコレクション
信頼できるプログラムを作る
オブジェクトでモデル化する
プロフェッショナルなPython
上級Python
例外は警報
第9章では、関数に契約を与えました。入力がその約束を破ったらどうなるでしょう。Pythonは今の道を止めて、例外を送出します。例外は怪物ではなく、役立つ情報です。
- 止まる 操作を完了できない
- 読む 最後の一行から
- 名前を知る 型とメッセージ
- 選ぶ 直す、拒否する、回復する
次の一行は、わざと失敗します。
minutes = int("forty")
トレースバックの最後はValueErrorのメッセージです。まずその一行を読み、次に上へ進んで自分のファイルの行を探します。型が違えば、壊れた約束も違います。int(None)はTypeError、10 / 0はZeroDivisionErrorです。
分かる警報だけを捕まえる
tryブロックは小さくします。自分が扱うつもりの危険な操作だけを入れましょう。
raw_minutes = "forty"
try:
minutes = int(raw_minutes)
except ValueError:
print("分数は整数で指定してください。")
else:
print("受理:", minutes)
出力:
分数は整数で指定してください。
except ValueErrorは、理解できる変換失敗だけを扱います。とにかく先へ進むためのexcept:やexcept Exceptionは避けます。名前の書き間違いや壊れた計算まで隠すからです。
後の整形はelseへ置きます。すると整形の不具合を、不正な入力と間違えません。複数の型をまとめるのは、その境界で本当に同じ扱いにするときだけです。たとえば文字列またはNoneを受ける境界なら、except (TypeError, ValueError)にできます。
四つの道には、四つの仕事
- try 危険な一歩を試す
- except 想定した失敗を扱う
- else 成功した結果を使う
- finally 必ず後片付けする
def show_average(total, count):
try:
average = total / count
except ZeroDivisionError:
print("平均を出す記録がありません。")
else:
print(f"平均:{average:.1f}")
finally:
print("計算終了。")
show_average(90, 3)
show_average(0, 0)
出力:
平均:30.0
計算終了。
平均を出す記録がありません。
計算終了。
elseは成功後だけ、finallyは成功、捕捉した例外、捕捉しない例外の後にも動きます。本当に必要な後片付けに使い、エラーや戻り値を隠すためには使いません。第12章では、ファイル用のもっと簡単な後片付け道具を学びます。
検証は門。推測ではない
変換と、意味の確認は別々の門です。"0"は整数の0へ変換できますが、0を許さないアプリもあります。
- 生の入力 "45" または "many"
- 変換する 整数にできる?
- 検証する 1から1440まで?
def parse_minutes(raw_minutes):
try:
minutes = int(raw_minutes)
except (TypeError, ValueError) as cause:
raise ValueError("分数は整数で指定してください") from cause
if not 1 <= minutes <= 1440:
raise ValueError("分数は1から1440までです")
return minutes
raise ... from causeは、呼び出し側へ安定したメッセージを渡しながら、元の変換失敗をerror.__cause__とトレースバックに残します。
オブジェクトの種類が違うならTypeError、種類は合っていて値が不正ならValueErrorを使います。必須の不正データを、勝手に0へ変えてはいけません。小さな端:int(True)は1になります。真偽値を分数として認めない契約なら、変換前にはっきり拒否します。
信頼できる学習ゲートを作る
次の完全なプログラムをstudy_gate.pyとして保存します。
def normalize_topic(raw_topic):
if not isinstance(raw_topic, str):
raise TypeError("テーマは文字列で指定してください")
topic = raw_topic.strip()
if not topic:
raise ValueError("テーマを空にはできません")
return topic
def parse_minutes(raw_minutes):
if isinstance(raw_minutes, bool):
raise TypeError("分数に真偽値は使えません")
try:
minutes = int(raw_minutes)
except (TypeError, ValueError) as cause:
raise ValueError("分数は整数で指定してください") from cause
if not 1 <= minutes <= 1440:
raise ValueError("分数は1から1440までです")
return minutes
def make_session(raw_topic, raw_minutes):
return {
"topic": normalize_topic(raw_topic),
"minutes": parse_minutes(raw_minutes),
}
def process_entries(raw_entries):
accepted = []
problems = []
for number, (topic, minutes) in enumerate(raw_entries, start=1):
try:
session = make_session(topic, minutes)
except (TypeError, ValueError) as error:
problems.append(f"記録{number}:{error}")
else:
accepted.append(session)
return accepted, problems
def format_report(sessions, problems):
total = 0
for session in sessions:
total += session["minutes"]
lines = [
f"受理:{len(sessions)}件",
f"拒否:{len(problems)}件",
f"信頼できる分数:{total}分",
]
for problem in problems:
lines.append("- " + problem)
return "\n".join(lines)
def run_checks():
assert normalize_topic(" Python ") == "Python"
assert parse_minutes("45") == 45
try:
parse_minutes("many")
except ValueError as error:
assert str(error) == "分数は整数で指定してください"
assert isinstance(error.__cause__, ValueError)
else:
raise AssertionError("不正な分数が受理されました")
run_checks()
raw_entries = [
(" Python ", "45"),
("Git", "many"),
(" ", "15"),
("SQL", "30"),
("テスト", "0"),
]
sessions, problems = process_entries(raw_entries)
print("確認に合格しました。")
print(format_report(sessions, problems))
python3 study_gate.pyで実行します。
確認に合格しました。
受理:2件
拒否:3件
信頼できる分数:75分
- 記録2:分数は整数で指定してください
- 記録3:テーマを空にはできません
- 記録5:分数は1から1440までです
コレクションの境界は、想定した検証失敗だけを捕捉します。プログラムの不具合は「不正な入力」と呼ばれず、見える状態のままです。
3つの小さなチャレンジ
- 1から5までの整数を扱う
parse_rating()を書き、0、1、5、6を試す。 - 辞書から
minutesキーを消し、KeyErrorだけを捕捉する。成功時の表示はelseへ置く。 - プロジェクトのデータへ
(42, "10")と("Git", True)を足し、二つのメッセージを予想する。
第11章へ進めるかな?
- トレースバックを最後の一行から読める
-
tryを小さくし、想定した例外型だけを捕捉できる -
except、else、finallyを説明できる - 変換してから、意味を検証できる
-
raise ... from ...で元の原因を残せる - 学習ゲートを実行し、すべての確認に合格した
次章では、信頼できる助手をモジュールとパッケージへ移し、プロジェクトごとの実行環境を作ります。