月次レポートv2
このレッスンでできるようになること
その月の合計、前の月との差、カテゴリ別の内訳をまとめて返す月次レポートを、中級の道具だけで組み立てられるようになります。
レポートは3つの部品でできています
入門で作った家計簿のレポートは、合計を出して終わりでした。v2では次の3つを出します。
- その月の合計金額
- 前の月と比べていくら増えたか減ったか
- カテゴリ別の内訳を、金額の大きい順に
どれも第3章と第4章でやったことの組み合わせです。演習では月別の抽出とカテゴリ別の集計・整形を渡し、合計と差額からレポートを組み立てる部分に集中します。
その月だけを取り出す
図書の貸出日を "2027-04-09" の形で持っておくと、月での絞り込みは文字列の先頭一致で書けます。
Python
april_books = [b for b in books if b["borrowed"].startswith("2027-04")]startswith は「その文字列で始まるか」を返すメソッドです。第3章の条件付き内包表記に、そのまま条件として置けます。
前の月を求める
次は雑誌の前号の月を求める例です。演習では同じ考え方の完成済み関数を渡します。
"2026-08" の前は "2026-07" です。ところが "2026-01" の前は "2025-12" で、年をまたぎます。ここは素直に数値に直して考えます。
Python
def previous_issue_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で埋める」という書き方です。7 が 07 になります。これを忘れると 2026-7 になり、startswith での比較が合わなくなります。
増減は符号を自分で付けます
図書の貸出数でも、差がプラスかマイナスかは、見た人にすぐ分かる形で出したいところです。
Python
change = borrowed_count - previous_count
sign = "+" if change >= 0 else "-"
line = f"貸出数の差 {sign}{abs(change)}冊"第3章の if-else 式が、こういう小さな分岐で効いてきます。abs は絶対値を返す組み込み関数で、これを挟むことで - が二重に付くのを防いでいます。
内訳は Counter と sorted で
カテゴリ別の集計は第2章の Counter、並べ替えは第4章の sorted と key です。次の図書の例では冊数の大きい順にしたいので、キーにマイナスを付けます。
Python
for genre, count in sorted(book_counts.items(), key=lambda pair: (-pair[1], pair[0])):
print(f"{genre} {count}冊")(-pair[1], pair[0]) はタプルのキーです。この例では冊数の降順で並び、冊数が同じときはジャンル名の昇順で並びます。演習の内訳でも、同じ考え方で金額とカテゴリ名の順を決めます。同額のときの順番を決めておかないと、実行するたびに並びが変わる可能性が残ります。レポートのように人が読むものは、いつ動かしても同じ順で出ることが大事です。
戻り値は1行1要素の文字列のリストにしておきます。こうしておくと、画面に出すのもファイルに書くのも呼ぶ側の自由になります。
リストを合計し、結果をつなぐ
数値のリストは sum で合計できます。空のリストなら0になります。次は図書のページ数の例です。
Python
page_total = sum([book["pages"] for book in books])
heading = [f"全体で{page_total}ページ"]
heading.append("貸出状況")
details = ["貸出中 3冊", "返却済み 2冊"]
result = heading + detailsappend は1要素を追加し、リスト同士の + は2つのリストを順につなぎます。
演習の補助関数は次の役割です。total_line(month, total) は合計の文字列1行、change_line(diff) は符号付きの増減の文字列1行を返します。category_lines(this_month) は当月の内訳の文字列リストを返し、支出が無ければ空のリストになります。月別の支出は this_month と last_month に用意済みです。これらを使って、合計・増減・内訳の順に並べたリストを返しましょう。
要件
- 完成済みの this_month と last_month から、それぞれ amount の合計を求める。空のリストの合計は0とする
- diff は当月の合計から前月の合計を引いた値にする
- total_line(month, total) で合計の行を作り、change_line(diff) で前月比の行を作る。この順で lines に入れる
- category_lines(this_month) が返す内訳のリストを lines の後ろにつないで返す
- 補助関数はそのまま使う。増減0円は 前月比 +0円 とし、内訳は金額の降順、同額ならカテゴリ名の昇順になる
- 対象月に支出が無いときは、合計0円と前月比の2行だけを返す。前月の年またぎは previous_month が処理する