python按行遍歷一個大文件,最優的語法應該是什麼?

目前寫了2種方法,

1.

for l in file.readlines():

2.

while l:
l = file.readline()

cPython2/3下,一個4百萬行的文件,方法1用了5.1秒,方法2用了5.9秒

pypy下,反而是方法2比較快,用了2.1秒,方法1用了3.4秒,不知是for慢了還是readlines慢了

------------------ 2015-03-02 補充 ---------------

3.

for l in file:

測試使用的系統是archlinux,用了 cPython2/3 pypy2 三個解釋器,同步到最新版本。

經過多次測試,總體來說方法3是最快的。

不過具體到解釋器也很重要,也發現一些有趣的現象:

  • cPython2下方法3明顯最快
  • pypy下方法2和3不相上下,用方法3橫向比較,pypy也是所有解釋器里最快的
  • 方法3在cPython3下要比cPython2下要慢一些,並且cPython3下方法3不能用 file.tell() (只有方法2可用),所以如果要顯示進度還挺麻煩。


理論上來說,總體上file.readlines()可以(取決於實現)不慢於你自己手動的一次次調用file.readline(),因為前者的循環在C語言層面,而你的循環是在Python語言層面。

但是在內存佔用上前者可能是後者的好幾十百倍,因為前者會一次性把所有數據讀取到內存中,而後者只每次讀取一行。

更好的寫法是:

with open("filename") as file:
for line in file:
do_things(line)


9我不會告訴你,其實直接可以這樣:

file = open(file_name)

for line in file:

dosomething(line)

不過這樣做,每一行會保留換行符

補充一下,由於手頭上沒有電腦,我不確定我這種方法是否比你的第一種快,但是你的第一種方法是一次性將文件的內容全部讀進一個list後再用for進行遍歷,而第二種是一次讀取一行處理,所以,第一種比第二種快是在理解範圍內的,至於pypy的問題,我個人的理解是pypy優化while比優化for優化得更多(猜測)。。如果是特大文件的話,不推薦使用第一種方法。

2015年3月1號再次補充

基於嚴謹的科學態度,今天做了測試,我之前提到的方法是不會一次性讀取所有文件的,使用660m的文件進行測試,

for i in file.readlines耗時1.5s

for i in file耗時0.86

while file.readline耗時3.3

而且,我還發現了一個更加神奇的事情,temp = file.readlines

for i in temp

比直接使用for i in file.readlines要快,耗時1.2s

最後測試了不同大小的文件,發現無論是大文件還是小文件,都是直接對文件對象進行for操作是最快的!

不過該結論局限於我自己的測試數據


除上面說的外,用生成器也可以。


with open("filename") as file:
for line in file:
do_things(line)

這是最快、最安全的方式


沒比較過,我一般用linecache函數


我用專欄里的一篇文章來答題。

專欄鏈接:給妹子講python,歡迎大家關注,提意見!

文件的遍歷

因為文件保存了很多字元和行,因此也是循環常見的典型使用案例,最原始的方法可以調用文件對象的read方法,把文件內容一次性載入至字元串對象

file = open("myfile.txt", "r")
print(file.read())

hello text file
goodbyt text file
Hahahahah

那麼如果想逐行讀取文本文件呢?for循環是最易於編寫及執行最快的選擇,這裡有兩種方法,

for line in open("myfile.txt","r").readlines():
print(line, end="")

for line in open("myfile.txt","r"):
print(line, end="")

hello text file
goodbyt text file
Hahahahah

這兩種方法的運行結果是一樣的,表面差別不大,但實際上有很大的區別:

第一種方法通過readlines方法,會首先一次性把文件載入到行字元串列表中,然後再對這個字元串列表進行迭代;

而第二種方法運行的原理則有所不同,他並非一次性將全部的文件內容載入到內存中,而是在迭代的時候,循環到了哪一行才將哪一行讀入到內存。這裡涉及到一個新的概念----迭代器(open函數返回的那個就是文件迭代器),專欄里的文章會著重系統介紹,歡迎關注。

現在我們只需要知道,第二種方法是文本文件讀取的最佳選擇,它簡單、且對任意大小的文件都有效,因為他不會一次性把整個文件都載入到內存中,相反第一種方法存在內存壓力過大的問題。


推薦閱讀:

ruby語言有什麼樣的美學特點?
寫一個實用水平的編譯器有多難,多大工作量?
直接看 ISO C++14 的標準文檔學習 C++ 可行嗎?
為什麼很少有用lisp描述演算法?
c和c++這類沒有gc的語言是不是騙自己?

TAG:編程語言 | Python | Python開發 |