つくる:何件でも記録

このレッスンで作るもの — 何件でも記録を受け取り、番号付きの一覧と合計を返す 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 になります。

diagram (will load when visible)

手元で動かしてみる

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. 合計行の手前に改行を入れ忘れる — 一覧の最後と 合計 がつながって 1 行になります。行を足すときは必ず "\n" を先に足します。
  2. 金額とカテゴリを文字列に変え忘れるrecord["price"] は数値なので、str を挟まないと TypeError です。record["category"] は最初から文字列なのでそのままつなげます。
  3. 空のときの分岐を書き忘れる — 記録が 0 件でもループは静かに 0 周で終わるため、エラーは出ません。記録がありません の行が抜けたまま気づかない、というのがありがちです。

かっこは半角、 は全角です。区切りの半角スペースの数もテストと一致させます。

やってみよう

関数 show_all を実装してください。引数 records は、namepricecategory をキーに持つ辞書が並んだリストです。

1 行目は === おこづかい帳 ===、続けて 1. りんご 120円 (食費) の形で記録を件数分、最後に 合計 370円 の形で合計を出します。改行 \n でつなぎ、末尾に改行は付けません。

records が空のリストのときは、見出しの次に 記録がありません を入れ、合計は 合計 0円 にします。

要件

  1. 関数名は show_all で、引数はリスト records の1つだけにする
  2. 1行目は "= おこづかい帳 ="、記録行は "1. りんご 120円 (食費)" の形にして 1 から番号を振る
  3. 最後の行は "合計 370円" の形で、全記録の price を足した合計を出す
  4. records が空のときは見出しの次に "記録がありません" を入れ、合計は 0円 にする
  5. 行の区切りは \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円"

ヒント

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

メモ

つくる:何件でも記録

⌘S で保存