つくる:保存機能
保存と読み戻しは、必ず対で作る
この章では、読み込み、書き込み、with、CSV、例外の受け止めを扱ってきました。最後にそれらを 1 本につなぎます。
作るのは save_and_load(path, records) です。渡された辞書のリストを保存し、そのファイルを読み戻して、元と同じ形の辞書のリスト を返します。入れたものと同じものが出てくるだけの地味な関数ですが、これが成り立つということは、アプリを閉じても記録が失われないということです。
手を付ける順番は次のとおりです。まず書き出す側から作ります。1 件を "品名,金額,カテゴリ" の行にして、行を改行でつなぎ、with で書き出します。ここまでは前の 2 回でやったことの組み合わせです。
次に読み戻す側です。with で読んで splitlines で行に分け、1 行ずつ split(",") で 3 つに分けて、辞書に組み直します。3 つに分かれた値は、タプルアンパックでそのまま 3 つの変数に受けられます。
片方だけ先に完成させると、書いた形式が読めないことに後から気づいて作り直しになります。1 件だけの記録で書いて読んで、往復できることを確かめてから件数を増やしてください。
ファイルから読んだ値は、すべて文字列
いちばん引っかかるのがここです。
Python
name, price, category = "りんご,120,食費".split(",")
print(price + 100)TypeError になります。price に入っているのは "120" という文字列で、数値ではありません。ファイルには文字しか入っていないので、読み戻した時点ではすべて str です。
辞書に入れる前に int を通します。忘れると、合計を計算するところで "120" + "80" が "12080" になる、という第 2 章で見た事故が起きます。見た目は似ているのでテストが落ちるまで気づきません。
書くときに str、読むときに int。この対称性が崩れると、型がじわじわ混ざって原因の分かりにくいバグになります。
0 件のときが、いちばん壊れやすい
記録が 0 件のときを先に確かめます。書き出す文字列は空になり、中身が空のファイルができます。読み戻すと read は "" を返します。
Python
print("".splitlines())
print("".split("\n"))[] と [''] です。splitlines なら for が 1 度も回らず、場合分けを書かずに空リストが返ります。split("\n") を使っていた場合は空文字が 1 件あることになり、それをカンマで 3 つに分けようとして ValueError で落ちます。
with を 1 つにまとめようとして詰まるのも定番です。書きモードで開いたファイルからは読めないので、書きと読みで 2 回に分けます。
やってみよう
関数 save_and_load(path, records) を実装してください。records を "品名,金額,カテゴリ" の行にして path に保存し、そのファイルを読み戻して辞書のリストに復元して返します。
キーは name、price、category の 3 つで、保存の順もこのとおりです。金額は保存時に文字列、復元時に int を通します。records が空リストのときは空リスト [] が返れば正解です。ファイルを開くときは with を使ってください。
要件
- 関数名は save_and_load で、引数は path と records の 2 つ
- 1 件を "品名,金額,カテゴリ" の行にし、改行でつないで path に書き出す
- ファイルを開くときは with を使う
- 書き出したファイルを読み戻し、split でカンマごとに分けて辞書に復元する
- 金額は int に戻し、文字列のままにしない
- records が空リストのときは空リストを返す