つくる 入力検証の例外設計
このレッスンでできるようになること。この章で覚えた道具だけを使い、家計簿の取り込み処理を「下の層で投げて、上の層で受け止める」形に組み上げられるようになります。新しい概念は足しません。
エラー処理の設計で一番大事なのは、投げる場所と受け止める場所を分けることです。データを 1 件ずつ見る検証関数は、おかしいと思ったら例外を投げるだけにします。何件処理したか、どこで止めるかを決めるのは、まとめ役の関数の仕事です。この分け方をしておくと、検証の規則を足すときに、まとめ役へ手を入れずに済みます。
今回組み上げるのは次の流れです。まず assert で、そもそも受け取った引数の形が正しいかを確かめます。次に 1 件ずつ検証関数へ渡し、InvalidExpenseError を受け止めて不備の一覧に貯めます。例外が出なかった件だけを else の節で受理します。最後に合計と予算を比べ、超えていれば BudgetOverError を投げて自分で受け止め、finally の節で処理の記録を残します。
class InvalidExpenseError(Exception):
passこのように、この章で書いた raise、カスタム例外、else、finally、assert がすべて 1 本の関数の中に並びます。どれも役割が違うので、置き場所を間違えないように読み返しながら書いてみてください。
要件
- InvalidExpenseError と BudgetOverError を Exception を継承して定義する
- validate は品名が空なら 品名がありません、金額が整数でなければ 品名 の金額が数値ではありません、金額がマイナスなら 品名 の金額がマイナスです を投げる
- import_expenses は records がリストでないことを assert で捕らえ、accepted と log を空、errors に前提のメッセージ、total を 0、status を 中止しました にした辞書を返す
- 検証を通った品名を accepted に、投げられたメッセージを errors に貯め、金額を total に足す
- total が budget を超えたら BudgetOverError を投げて受け止め、status を 警告 メッセージ にする。超えなければ 予算内です 残り 残額 円 にする
- finally の節で log に 検証を終えました 受理 件数 件 を追加する
- 返す辞書のキーは accepted, errors, total, status, log とする
入出力例
import_expenses([{"amount":250,"name":"ノート"},{"amount":100,"name":""},{"amount":"180","name":"牛乳"}], 1000) → {"accepted":["ノート"],"errors":["品名がありません","牛乳 の金額が数値ではありません"],"log":["検証を終えました 受理 1 件"],"status":"予算内です 残り 750 円","total":250}
import_expenses([{"amount":60000,"name":"家賃"},{"amount":-500,"name":"返金"}], 50000) → {"accepted":["家賃"],"errors":["返金 の金額がマイナスです"],"log":["検証を終えました 受理 1 件"],"status":"警告 予算を 10000 円超えています","total":60000}
import_expenses("ノート", 1000) → {"accepted":[],"errors":["records はリストで渡してください"],"log":[],"status":"中止しました","total":0}ヒント
編集 LuaGate編集部