[Python-Dev] Use for enumerate()

Tim Peters tim.one@comcast.net
Fri, 26 Apr 2002 20:56:31 -0400


[Guido]
> Here's a cute use for enumerate(), now that it's checked in.
> ...
> A function that reads forward until the right line is of course easily
> written for any version of Python; but enumerate() seems a
> particularly good fit here since it avoids the need to have a separate
> counter.  This also shows how useful it is that files are iterators!
>
>     def getline(filename, lineno):
> 	if lineno < 1:
> 	    return ''
> 	lineno -= 1
> 	f = open(filename)
> 	for i, line in enumerate(f):
> 	    if i == lineno:
> 		break
> 	else:
> 	    line = ''
> 	f.close()
> 	return line
>
> Challenge 1: do it faster.

Challenge 0:  Stop posting Python code with stinking tabs <wink>.

The attached g2 is about 60% quicker across the text files I tried it on,
using this timing driver (which sums the time across all interesting inputs;
note that, overall, this is quadratic-time in the number or lines for either
method):

FNAME = "whatever"

def drive():
    from time import clock as now
    f = file(FNAME)
    n = len(f.readlines())
    f.close()
    indices = range(n+2)

    for func in getline, g2:
        start = now()
        for i in indices:
            func(FNAME, i)
        finish = now()
        print func.__name__, finish - start

> Challenge 2: do it with less code.

Measured by bytes, lines, statements, or conceptual pain <wink>?

> Challenge 3: do it faster and with less code.

That's a tough one.

Here's g2.  It's a non-ambitious member of the "reduce the number of trips
around the eval loop" school of optimization:

def g2(filename, lineno):
    offset = lineno - 1
    if offset < 0:
        return ''
    line = ''
    f = file(filename)
    lines = True
    while lines:
        lines = f.readlines(5000)
        n = len(lines)
        if offset >= n:
            offset -= n
            continue
        line = lines[offset]
        break
    f.close()
    return line