月次レポートv2

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

その月の合計、前の月との差、カテゴリ別の内訳をまとめて返す月次レポートを、中級の道具だけで組み立てられるようになります。

レポートは3つの部品でできています

入門で作った家計簿のレポートは、合計を出して終わりでした。v2では次の3つを出します。

  • その月の合計金額
  • 前の月と比べていくら増えたか減ったか
  • カテゴリ別の内訳を、金額の大きい順に

どれも第3章と第4章でやったことの組み合わせです。新しい文法は出てきません。

その月だけを取り出す

日付を "2026-08-01" の形で持っておくと、月での絞り込みは文字列の先頭一致で書けます。

this_month = [e for e in expenses if e["date"].startswith("2026-08")]

startswith は「その文字列で始まるか」を返すメソッドです。第3章の条件付き内包表記に、そのまま条件として置けます。

前の月を求める

"2026-08" の前は "2026-07" です。ところが "2026-01" の前は "2025-12" で、年をまたぎます。ここは素直に数値に直して考えます。

def previous_month(month): year, m = month.split("-") year, m = int(year), int(m) if m == 1: return f"{year - 1}-12" return f"{year}-{m - 1:02d}"

{m - 1:02d} は「2桁の整数、足りない桁は0で埋める」という書き方です。707 になります。これを忘れると 2026-7 になり、startswith での比較が合わなくなります。

増減は符号を自分で付けます

差がプラスかマイナスかは、見た人にすぐ分かる形で出したいところです。

diff = total - prev_total sign = "+" if diff >= 0 else "-" line = f"前月比 {sign}{abs(diff)}円"

第3章の if-else 式が、こういう小さな分岐で効いてきます。abs は絶対値を返す組み込み関数で、これを挟むことで - が二重に付くのを防いでいます。

内訳は Counter と sorted で

カテゴリ別の集計は第2章の Counter、並べ替えは第4章の sortedkey です。金額の大きい順にしたいので、キーにマイナスを付けます。

for category, amount in sorted(totals.items(), key=lambda kv: (-kv[1], kv[0])): print(f"{category} {amount}円")

(-kv[1], kv[0]) はタプルのキーです。まず金額の降順で並び、金額が同じときはカテゴリ名の昇順で並びます。同額のときの順番を決めておかないと、実行するたびに並びが変わる可能性が残ります。レポートのように人が読むものは、いつ動かしても同じ順で出ることが大事です。

戻り値は1行1要素の文字列のリストにしておきます。こうしておくと、画面に出すのもファイルに書くのも呼ぶ側の自由になります。

要件

  1. previous_month(month) を書く。2026-08 なら 2026-07、2026-01 なら 2025-12 を返す
  2. 月は必ず2桁にする。2026-7 のような形にしない
  3. monthly_report(expenses, month) は行の文字列を並べたリストを返す
  4. 1行目は 2026-08 の合計 6130円 の形にする
  5. 2行目は 前月比 +1050円 の形にする。減っているときは 前月比 -300円 とする
  6. 3行目以降はその月のカテゴリ別合計を、金額の降順、同額ならカテゴリ名の昇順で 食費 4050円 の形で並べる
  7. 対象の月に支出が1件も無いときは、合計0円と前月比の2行だけを返す

入出力例

monthly_report([{"amount":2900,"category":"食費","date":"2026-07-03","name":"スーパー"},{"amount":1200,"category":"交通費","date":"2026-07-10","name":"電車代"},{"amount":980,"category":"食費","date":"2026-07-22","name":"ランチ"},{"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":"技術書"}], "2026-08")["2026-08 の合計 6130円","前月比 +1050円","食費 4050円","教養 1600円","交通費 480円"] monthly_report([{"amount":5000,"category":"交際費","date":"2025-12-20","name":"忘年会"},{"amount":300,"category":"交際費","date":"2026-01-01","name":"初詣"},{"amount":4400,"category":"食費","date":"2026-01-06","name":"スーパー"}], "2026-01")["2026-01 の合計 4700円","前月比 -300円","食費 4400円","交際費 300円"] monthly_report([{"amount":2900,"category":"食費","date":"2026-07-03","name":"スーパー"},{"amount":1200,"category":"交通費","date":"2026-07-10","name":"電車代"},{"amount":980,"category":"食費","date":"2026-07-22","name":"ランチ"},{"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":"技術書"}], "2026-09")["2026-09 の合計 0円","前月比 -6130円"]

ヒント

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

メモ

月次レポートv2

⌘S で保存