つくる 入力検証の例外設計

このレッスンでできるようになること。この章で覚えた道具だけを使い、家計簿の取り込み処理を「下の層で投げて、上の層で受け止める」形に組み上げられるようになります。新しい概念は足しません。

エラー処理の設計で一番大事なのは、投げる場所と受け止める場所を分けることです。データを 1 件ずつ見る検証関数は、おかしいと思ったら例外を投げるだけにします。何件処理したか、どこで止めるかを決めるのは、まとめ役の関数の仕事です。この分け方をしておくと、検証の規則を足すときに、まとめ役へ手を入れずに済みます。

今回組み上げるのは次の流れです。まず assert で、そもそも受け取った引数の形が正しいかを確かめます。次に 1 件ずつ検証関数へ渡し、InvalidExpenseError を受け止めて不備の一覧に貯めます。例外が出なかった件だけを else の節で受理します。最後に合計と予算を比べ、超えていれば BudgetOverError を投げて自分で受け止め、finally の節で処理の記録を残します。

class InvalidExpenseError(Exception): pass

このように、この章で書いた raise、カスタム例外、elsefinallyassert がすべて 1 本の関数の中に並びます。どれも役割が違うので、置き場所を間違えないように読み返しながら書いてみてください。

要件

  1. InvalidExpenseError と BudgetOverError を Exception を継承して定義する
  2. validate は品名が空なら 品名がありません、金額が整数でなければ 品名 の金額が数値ではありません、金額がマイナスなら 品名 の金額がマイナスです を投げる
  3. import_expenses は records がリストでないことを assert で捕らえ、accepted と log を空、errors に前提のメッセージ、total を 0、status を 中止しました にした辞書を返す
  4. 検証を通った品名を accepted に、投げられたメッセージを errors に貯め、金額を total に足す
  5. total が budget を超えたら BudgetOverError を投げて受け止め、status を 警告 メッセージ にする。超えなければ 予算内です 残り 残額 円 にする
  6. finally の節で log に 検証を終えました 受理 件数 件 を追加する
  7. 返す辞書のキーは 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編集部
main.py
学習モード

メモ

つくる 入力検証の例外設計

⌘S で保存