つくる:何件でも記録
このレッスンで作るもの — 何件でも記録を受け取り、番号付きの一覧と合計を返す
show_allを作ります。おこづかい帳が「1 件だけのアプリ」を卒業します。
つくる — 何件でも記録
第 1 章の make_receipt は 2 行が決め打ちでした。第 2 章で品名と金額を受け取れるようになりましたが、それでも 1 件だけです。この章でループを覚えたので、いよいよ 件数の縛りを外します。
作るのは show_all(records) です。記録の集まりを受け取り、番号付きの一覧と合計を 1 本の文字列にして返します。
「何件でも」は、アプリが道具になるための最低条件です。ここを越えると、おこづかい帳として実際に使えるものになります。
記録の形
支出 1 件は、下記のような 辞書 で表します。
{"name": "りんご", "price": 120, "category": "食費"}品名が name、金額が price、カテゴリが category です。中身を取り出すときは record["name"] のように、角かっこにキーの名前を書きます。
辞書そのものの作り方や書き換え方は第 7 章で詳しく扱います。ここでは「キーを指定して値を取り出す」ところだけ使います。第 4 章の guess_category が返していたカテゴリが、この category に入る、と考えてください。
記録の集まりは、この辞書を並べたリストです。
records = [
{"name": "りんご", "price": 120, "category": "食費"},
{"name": "パン", "price": 250, "category": "食費"},
]出力の形を決める
show_all(records) が返す文字列は下記のとおりです。上の records を渡した場合の結果です。
=== おこづかい帳 ===
1. りんご 120円 (食費)
2. パン 250円 (食費)
合計 370円見出しが 1 行、記録が件数分、最後に合計が 1 行です。番号は 1 から始まり、金額のうしろに半角かっこでカテゴリを添えます。末尾に改行は付けません。
記録が 1 件もないときは、代わりに 記録がありません の 1 行を入れます。
=== おこづかい帳 ===
記録がありません
合計 0円空のときに何を出すかを決めておくのは、地味ですが大事な設計です。決めていないと、見出しと合計だけの不思議な画面が出ます。
組み立てる
見出しから始めて、1 件ずつ足していきます。番号は enumerate、金額の足し上げは for の合計、どちらもこの章で扱ったものです。
def show_all(records):
lines = "=== おこづかい帳 ==="
total = 0
count = 0
for i, record in enumerate(records, 1):
lines = lines + "\n" + str(i) + ". " + record["name"] + " " + str(record["price"]) + "円 (" + record["category"] + ")"
total = total + record["price"]
count = count + 1
if count == 0:
lines = lines + "\n記録がありません"
lines = lines + "\n合計 " + str(total) + "円"
return lines一覧を作りながら、同じループの中で合計も足しています。2 回まわす必要はありません。count は「1 件も無かったか」を判定するためのカウンタです。
1 行を組み立てるところが長くなってきました。第 2 章の f-string を使うと、下記のようにすっきりします。結果はまったく同じです。
line = f"{i}. {record['name']} {record['price']}円 ({record['category']})"f-string の中で辞書のキーを書くときは、外側が二重クオートなら内側はシングルクオートにします。同じ記号で入れ子にすると、そこで文字列が終わったと解釈されて SyntaxError になります。
手元で動かしてみる
kakeibo.py に下記を書いて実行すると、一覧が画面に出ます。
records = [
{"name": "りんご", "price": 120, "category": "食費"},
{"name": "パン", "price": 250, "category": "食費"},
]
print(show_all(records))records を書き換えれば、件数がいくつでもそのまま動きます。ここが第 2 章までとの決定的な違いです。
前のレッスンの collect_until_end と組み合わせれば、input() で受け取った品名を records に貯めて show_all で表示する、という一連の流れが作れます。第 6 章では、その流れを関数に分けて整理します。
この
show_allは第 9 章の完成形まで生き残ります。カテゴリ別集計もファイル保存も、この一覧の上に積み上がります。
よくある間違い
- 合計行の手前に改行を入れ忘れる — 一覧の最後と
合計がつながって 1 行になります。行を足すときは必ず"\n"を先に足します。 - 金額とカテゴリを文字列に変え忘れる —
record["price"]は数値なので、strを挟まないとTypeErrorです。record["category"]は最初から文字列なのでそのままつなげます。 - 空のときの分岐を書き忘れる — 記録が 0 件でもループは静かに 0 周で終わるため、エラーは出ません。
記録がありませんの行が抜けたまま気づかない、というのがありがちです。
かっこは半角、円 は全角です。区切りの半角スペースの数もテストと一致させます。
やってみよう
関数 show_all を実装してください。引数 records は、name と price と category をキーに持つ辞書が並んだリストです。
1 行目は === おこづかい帳 ===、続けて 1. りんご 120円 (食費) の形で記録を件数分、最後に 合計 370円 の形で合計を出します。改行 \n でつなぎ、末尾に改行は付けません。
records が空のリストのときは、見出しの次に 記録がありません を入れ、合計は 合計 0円 にします。
要件
- 関数名は show_all で、引数はリスト records の1つだけにする
- 1行目は "= おこづかい帳 ="、記録行は "1. りんご 120円 (食費)" の形にして 1 から番号を振る
- 最後の行は "合計 370円" の形で、全記録の price を足した合計を出す
- records が空のときは見出しの次に "記録がありません" を入れ、合計は 0円 にする
- 行の区切りは \n を使い、末尾には改行を付けない
入出力例
show_all([{"category":"食費","name":"りんご","price":120},{"category":"食費","name":"パン","price":250}]) → "=== おこづかい帳 ===
1. りんご 120円 (食費)
2. パン 250円 (食費)
合計 370円"
show_all([{"category":"交通費","name":"電車","price":320}]) → "=== おこづかい帳 ===
1. 電車 320円 (交通費)
合計 320円"
show_all([{"category":"食費","name":"牛乳","price":200},{"category":"日用品","name":"洗剤","price":480},{"category":"娯楽","name":"映画","price":1800}]) → "=== おこづかい帳 ===
1. 牛乳 200円 (食費)
2. 洗剤 480円 (日用品)
3. 映画 1800円 (娯楽)
合計 2480円"
show_all([{"category":"その他","name":"おまけ","price":0},{"category":"食費","name":"パン","price":250}]) → "=== おこづかい帳 ===
1. おまけ 0円 (その他)
2. パン 250円 (食費)
合計 250円"
show_all([]) → "=== おこづかい帳 ===
記録がありません
合計 0円"