ファイルを読み込む

このレッスンで作るもの — openread でテキストファイルを読み込み、1 行ずつのリストに変える read_lines を作ります。

ファイルを読み込む

ここまでのおこづかい帳は、プログラムを終了すると記録がすべて消えていました。変数もリストも辞書も、メモリの上にしかないからです。次に起動したときも同じ記録を見られるようにするには、内容を ファイル に残す必要があります。

第 8 章では「保存できるおこづかい帳」を目指します。最初の一歩は、すでにあるファイルを読み込むところからです。

ファイルは、プログラムが終わっても消えない置き場所です。変数がメモの走り書きだとすれば、ファイルは引き出しにしまったノートにあたります。

open と read の書き方

ファイルを扱うときは、まず open でファイルを開きます。第 1 引数がファイルのパス、第 2 引数がモードです。読み込みのモードは "r" を指定します。

f = open("kakeibo.txt", "r", encoding="utf-8") text = f.read() f.close()

open が返す fファイルオブジェクト と呼ばれ、ファイルを操作するための取っ手のようなものです。read を呼ぶと、中身が丸ごと 1 本の文字列として返ってきます。使い終わったら close で閉じます。

encoding="utf-8" は文字コードの指定です。日本語を含むファイルではこれを付けないと、環境によって文字化けしたりエラーになったりします。付ける癖を付けておくと事故が減ります。

読み込んだ文字列を行に分ける

read が返すのは 1 本の長い文字列です。ファイルの中に 3 行書いてあれば、改行 \n が 2 つ入った文字列になります。

text = "りんご,120,食費\nみかん,80,食費"

これを 1 行ずつのリストにするには splitlines を使います。split("\n") でもほぼ同じことができますが、splitlines は末尾の改行によって空文字が増えないので安全です。

lines = text.splitlines() # ["りんご,120,食費", "みかん,80,食費"]

ファイルの最後に改行が 1 つ入っていることはよくあります。split("\n") だと最後に "" という空の要素が付いてしまい、後の処理で「品名が空の支出」が混ざる原因になります。

空文字の混入は、その場ではエラーにならず、集計の段になって初めて表面化します。取り込む入口で形をそろえておくのが一番安上がりです。

学習環境では書いてから読む

この演習では、read_lines(path, text) のようにファイルの中身も引数で受け取ります。関数の中でまず pathtext を書き出し、そのうえで読み戻す形にします。

学習環境の都合で、あらかじめ用意されたファイルを置いておけないためです。手元のパソコンでは、すでにあるファイルを読むだけで構いません。書き込みの部分は次のレッスンで詳しく扱います。

diagram (will load when visible)

動きを追ってみる

read_lines("/tmp/kakeibo.txt", "りんご,120,食費\nみかん,80,食費") を呼んだときの流れを追います。

  1. /tmp/kakeibo.txt を書き込みモードで開き、渡された文字列をそのまま書く
  2. 同じパスを読み込みモードで開き直す
  3. read"りんご,120,食費\nみかん,80,食費" を得る
  4. splitlines["りんご,120,食費", "みかん,80,食費"] になる
  5. そのリストが戻り値になる

中身が空文字 "" のときは、splitlines の結果も空リスト [] になります。「まだ 1 件も記録がない」状態が自然に表現できます。

空のときに空リストが返る、というのは地味ですが大事な性質です。呼び出す側が場合分けを書かずに for で回せます。

よくある間違い

  1. close を書き忘れる — 開いたまま放置するとファイルが解放されず、書き込んだ内容が反映されないことがあります。次のレッスンで学ぶ with を使えばこの問題は消えます。
  2. モードを間違える — 読むつもりで "w" を渡すと、ファイルの中身が空になってしまいます。"r" が読み、"w" が書きです。
  3. 戻り値が文字列のままread の結果をそのまま return すると、行のリストではなく 1 本の文字列が返ります。splitlines を通してからにします。

print(text) で確かめて満足するのもよくある落とし穴です。採点は戻り値だけを見るので、必ず return で返してください。

やってみよう

関数 read_lines(path, text) を実装してください。まず pathtext を書き出し、そのうえで同じファイルを読み込み、splitlines で行のリストにして返します。

文字コードは encoding="utf-8" を指定します。text が空文字のときは空リスト [] が返る形になっていれば正解です。末尾に改行が付いた文字列を渡しても、余分な空要素が増えないことを確かめてみてください。

要件

  1. 関数名は read_lines で、引数は path と text の 2 つ
  2. 先に path を書き込みモードで開き、text をそのまま書き出す
  3. 同じ path を読み込みモードで開き、read で中身を取得する
  4. splitlines で行のリストにして return する
  5. open には encoding="utf-8" を指定する

入出力例

read_lines("/tmp/kakeibo_read_1.txt", "りんご,120,食費 みかん,80,食費") → ["りんご,120,食費","みかん,80,食費"] read_lines("/tmp/kakeibo_read_2.txt", "ノート,200,日用品")["ノート,200,日用品"] read_lines("/tmp/kakeibo_read_3.txt", "")[] read_lines("/tmp/kakeibo_read_4.txt", "パン,150,食費 牛乳,180,食費 ") → ["パン,150,食費","牛乳,180,食費"] read_lines("/tmp/kakeibo_read_5.txt", "バス,220,交通費 映画,1800,娯楽 洗剤,380,日用品") → ["バス,220,交通費","映画,1800,娯楽","洗剤,380,日用品"]

ヒント

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

メモ

ファイルを読み込む

⌘S で保存