Eu tive que postar isso em uma pergunta semelhante até que minha pontuação de reputação subisse um pouco (graças a quem me bateu!).
Todas essas soluções ignoram uma maneira de tornar essa execução consideravelmente mais rápida, usando a interface não armazenada em buffer (bruta), usando bytearrays e fazendo seu próprio buffer. (Isso só se aplica no Python 3. No Python 2, a interface bruta pode ou não ser usada por padrão, mas no Python 3, você usará o Unicode como padrão.)
Usando uma versão modificada da ferramenta de temporização, acredito que o código a seguir é mais rápido (e marginalmente mais pitônico) do que qualquer uma das soluções oferecidas:
def rawcount(filename):
f = open(filename, 'rb')
lines = 0
buf_size = 1024 * 1024
read_f = f.raw.read
buf = read_f(buf_size)
while buf:
lines += buf.count(b'\n')
buf = read_f(buf_size)
return lines
Usando uma função de gerador separada, isso executa um smidge mais rápido:
def _make_gen(reader):
b = reader(1024 * 1024)
while b:
yield b
b = reader(1024*1024)
def rawgencount(filename):
f = open(filename, 'rb')
f_gen = _make_gen(f.raw.read)
return sum( buf.count(b'\n') for buf in f_gen )
Isso pode ser feito completamente com expressões de geradores in-line usando itertools, mas fica muito estranho:
from itertools import (takewhile,repeat)
def rawincount(filename):
f = open(filename, 'rb')
bufgen = takewhile(lambda x: x, (f.raw.read(1024*1024) for _ in repeat(None)))
return sum( buf.count(b'\n') for buf in bufgen )
Aqui estão os meus horários:
function average, s min, s ratio
rawincount 0.0043 0.0041 1.00
rawgencount 0.0044 0.0042 1.01
rawcount 0.0048 0.0045 1.09
bufcount 0.008 0.0068 1.64
wccount 0.01 0.0097 2.35
itercount 0.014 0.014 3.41
opcount 0.02 0.02 4.83
kylecount 0.021 0.021 5.05
simplecount 0.022 0.022 5.25
mapcount 0.037 0.031 7.46