読者です 読者をやめる 読者になる 読者になる

ファイルを読み込む時のreadlines関数について

Pythonではファイルへアクセスするのにファイルオブジェクトを用います。openというビルトイン関数を用いることでファイルオブジェクトを作成します。

>>> f = open('text.txt')
>>> type(f)

>>> f.readline()
'一行目の内容'
>>> f.readlines()
['二行目の内容', '三行目の内容', ...]

open関数では処理モードはデフォルトで‘r’なので、上記はtext.txtを入力モードで開きます。

このfを使って、text.txtファイルの内容を1行ずつ読み込む処理をする場合上記のreadlines関数を用いて

>>> for line in open('text.txt').readlines():
...     print line,
...
一行目の内容
二行目の内容
・・・
EOF(実際は表示されない)

とするのが普通でしたが、最近のPythonのバージョンでは

>>> for line in open('text.txt'):
(あとは同じ)

とすることを、コードがシンプルで分りやすい・実行速度が上がる・メモリが節約できる、という3点から推奨しています。

1点目コードがシンプルで分りやすいのは、見れば分ります。

3点目のメモリが節約できるというのはreadlines()の場合、一旦ファイルの内容を全てリストに直してそれを使ってforループをさせるのですが、その際リストがメモリの容量を消費することを指しています。一方、推奨されている方法では一行ずつ読み込んではline変数に代入する、ということを繰り返すのでメモリの消費が抑えられます。

で、2点目に関して、実際問題どれくらい早くなるのでしょうか?ということのが本題。

と言う訳で試してみます。コードはこんな感じ
timetest.py

import time
t1 = time.time()
for line in open('test.txt').readlines():
    print line,
t2 = time.time()
for line in open('test.txt'):
    print line,
t3 = time.time()

さて、test.txtに

hogehoge

という行を、1行,100行,10000行,1000000行入れて測定した結果が下のテーブル

test.txtの行数 readlines(t2-t1) 推奨(t3-t2) 勝者
1(9B) 0.000370025634766 0.000186920166016 推奨
100(900B) 0.00901699066162 0.00909399986267 readlines
10000(90KB) 0.221387147903 0.211538791656 推奨
1000000(9MB) 8.83639001846 7.82622599602 推奨

考察

  • 読み込むファイルの大きさがそこそこな大きさ(数十KBくらい?)まではファイルをすべてメモリにキャッシュした方が実行時間が速い
  • ファイルがもっと大きくなると、逆転が起きてどんどん差が開いていく

結論

違いが如実に現れる程大きなファイルを扱うことはないかも知れないけど、他のプロセスとの兼ね合いもあるし、ここは素直に推奨されてる方法で行った方がよさそうですね。