自由拡張

このレッスンでできるようになること

家計簿に自分で欲しい機能を1つ足すときの、決め方と組み立て方が身に付きます。ここでは予算アラートを題材にします。

まず「何を入れて何が出るか」を決めます

機能を足したくなったとき、いきなりコードを書き始めると手が止まります。先に決めるのは次の2つです。

  • 入力 — その機能は何を受け取るのか
  • 出力 — 何を返すのか。表示するのか、値を返すのか

今回の予算アラートなら、入力は「支出のリスト」と「カテゴリごとの予算」の2つ、出力は「予算を超えたカテゴリの警告文のリスト」です。これが決まれば、あとは中を埋めるだけになります。

def budget_alerts(expenses, budgets): ...

budgets はカテゴリ名から金額への辞書にします。{"食費": 30000, "交通費": 5000} のような形です。

表示ではなく値を返します

ここで print してしまいたくなりますが、我慢してリストを返す形にします。値を返しておくと、画面に出すことも、ファイルに書くことも、件数だけ数えることも、呼ぶ側で選べます。第7章までのレポート関数を全部この形にしてきたのと同じ理由です。

そして値を返す関数は、前のレッスンで書いたチェックスクリプトで assert できます。print する関数は目で見るしかありません。

中身はここまでの道具だけです

集計は第2章の Counter、絞り込みは第3章の内包表記、並べ替えは第4章の sortedkey です。

overs = [ (category, totals[category] - limit) for category, limit in budgets.items() if totals[category] > limit ]

budgets.items() を回しているのがポイントです。支出のほうを回すと、予算を決めていないカテゴリまで対象になってしまいます。予算を決めたカテゴリだけを見たいので、予算の辞書を主役にします。

totals[category]Counter なので、そのカテゴリの支出が1件も無くても 0 が返ります。第2章で defaultdictCounter を学んだときの、KeyError を出さない性質がここで効きます。

並び順を決めておきます

超過額の大きい順に並べます。同じ超過額のときはカテゴリ名の昇順にして、いつ動かしても同じ順になるようにします。

overs.sort(key=lambda pair: (-pair[1], pair[0]))

あとは1行ずつの文にするだけです。ここまで、新しい文法は1つも出てきていません。7章ぶんの道具で、新しい機能が1つ増えました。

要件

  1. budget_alerts(expenses, budgets) は文字列のリストを返す
  2. budgets は カテゴリ名 から 予算額 への辞書とする
  3. 予算が決められているカテゴリだけを対象にする。予算に無いカテゴリは無視する
  4. 支出の合計が予算を超えたときだけ警告する。ちょうど同額のときは警告しない
  5. 警告文は 食費 は予算を1050円超えています の形にする
  6. 超過額の大きい順に並べる。同じ超過額のときはカテゴリ名の昇順にする
  7. 超過が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円超えています"]

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.py
学習モード

メモ

自由拡張

⌘S で保存