自由拡張
このレッスンでできるようになること
家計簿に自分で欲しい機能を1つ足すときの、決め方と組み立て方が身に付きます。ここでは予算アラートを題材にします。
まず「何を入れて何が出るか」を決めます
機能を足したくなったとき、いきなりコードを書き始めると手が止まります。先に決めるのは次の2つです。
- 入力 — その機能は何を受け取るのか
- 出力 — 何を返すのか。表示するのか、値を返すのか
今回の予算アラートなら、入力は「支出のリスト」と「カテゴリごとの予算」の2つ、出力は「予算を超えたカテゴリの警告文のリスト」です。これが決まれば、あとは中を埋めるだけになります。
def budget_alerts(expenses, budgets):
...budgets はカテゴリ名から金額への辞書にします。{"食費": 30000, "交通費": 5000} のような形です。
表示ではなく値を返します
ここで print してしまいたくなりますが、我慢してリストを返す形にします。値を返しておくと、画面に出すことも、ファイルに書くことも、件数だけ数えることも、呼ぶ側で選べます。第7章までのレポート関数を全部この形にしてきたのと同じ理由です。
そして値を返す関数は、前のレッスンで書いたチェックスクリプトで assert できます。print する関数は目で見るしかありません。
中身はここまでの道具だけです
集計は第2章の Counter、絞り込みは第3章の内包表記、並べ替えは第4章の sorted と key です。
overs = [
(category, totals[category] - limit)
for category, limit in budgets.items()
if totals[category] > limit
]budgets.items() を回しているのがポイントです。支出のほうを回すと、予算を決めていないカテゴリまで対象になってしまいます。予算を決めたカテゴリだけを見たいので、予算の辞書を主役にします。
totals[category] は Counter なので、そのカテゴリの支出が1件も無くても 0 が返ります。第2章で defaultdict と Counter を学んだときの、KeyError を出さない性質がここで効きます。
並び順を決めておきます
超過額の大きい順に並べます。同じ超過額のときはカテゴリ名の昇順にして、いつ動かしても同じ順になるようにします。
overs.sort(key=lambda pair: (-pair[1], pair[0]))あとは1行ずつの文にするだけです。ここまで、新しい文法は1つも出てきていません。7章ぶんの道具で、新しい機能が1つ増えました。
要件
- budget_alerts(expenses, budgets) は文字列のリストを返す
- budgets は カテゴリ名 から 予算額 への辞書とする
- 予算が決められているカテゴリだけを対象にする。予算に無いカテゴリは無視する
- 支出の合計が予算を超えたときだけ警告する。ちょうど同額のときは警告しない
- 警告文は 食費 は予算を1050円超えています の形にする
- 超過額の大きい順に並べる。同じ超過額のときはカテゴリ名の昇順にする
- 超過が1件も無いときは空のリストを返す
入出力例
budget_alerts([{"amount":3200,"category":"食費","date":"2026-08-01","name":"スーパー"},{"amount":480,"category":"交通費","date":"2026-08-02","name":"電車代"},{"amount":850,"category":"食費","date":"2026-08-03","name":"コンビニ"},{"amount":1600,"category":"教養","date":"2026-08-05","name":"技術書"}], {"交通費":5000,"教養":1000,"食費":3000}) → ["食費 は予算を1050円超えています","教養 は予算を600円超えています"]
budget_alerts([{"amount":3200,"category":"食費","date":"2026-08-01","name":"スーパー"},{"amount":480,"category":"交通費","date":"2026-08-02","name":"電車代"},{"amount":850,"category":"食費","date":"2026-08-03","name":"コンビニ"},{"amount":1600,"category":"教養","date":"2026-08-05","name":"技術書"}], {"交通費":480,"教養":1550,"食費":4000}) → ["教養 は予算を50円超えています","食費 は予算を50円超えています"]
budget_alerts([{"amount":3200,"category":"食費","date":"2026-08-01","name":"スーパー"},{"amount":480,"category":"交通費","date":"2026-08-02","name":"電車代"},{"amount":850,"category":"食費","date":"2026-08-03","name":"コンビニ"},{"amount":1600,"category":"教養","date":"2026-08-05","name":"技術書"}], {"交通費":100,"娯楽":0}) → ["交通費 は予算を380円超えています"]