how to append to a list twice?

Alex Martelli aleaxit at yahoo.com
Sat Apr 22 02:36:07 EDT 2006


Fredrik Lundh <fredrik at pythonware.com> wrote:

> Alex Martelli wrote:
> 
> > > But of course that only does it once, and I don't want to have to copy
> > > and paste the append line. Perhaps there's a better way than this.
> >
> > def makeseries(N):
> >   series = [N]
> >   append = series.append
> >   for tailer in xrange(N-1, -1, -1):
> >     append(tailer)
> >     append(tailer)
> 
> But Now You've Violated The DRY Principle!!!

Just as with any other unrolled loop, yes -- loop unrolling is an
optimization which is based exactly on exchanging some textual
repetition for a tiny bit more speed.

Of course, optimizations can easily be premature, and in any case need
to be checked by measurement.  E.g., here are a few variations:

def makeseries_a(N):
  series = [N]
  append = series.append
  for tailer in xrange(N-1, -1, -1):
    append(tailer)
    append(tailer)
  return series

def makeseries_b(N):
  series = [N]
  append = series.append
  for tailer in xrange(N-1, -1, -1):
      for x in (1,2):
        append(tailer)
  return series

def makeseries_c(N):
  series = [N]
  extend = series.extend
  for tailer in xrange(N-1, -1, -1):
    extend((tailer,tailer))
  return series

def makeseries_d(N):
  series = [N]
  extend = series.extend
  for tailer in xrange(N-1, -1, -1):
    extend((tailer,)*2)
  return series


And:

brain:~/downloads alex$ python -mtimeit -s'import rep'
'rep.makeseries_a(100)'
10000 loops, best of 3: 31.7 usec per loop
brain:~/downloads alex$ python -mtimeit -s'import rep'
'rep.makeseries_b(100)'
10000 loops, best of 3: 57.4 usec per loop
brain:~/downloads alex$ python -mtimeit -s'import rep'
'rep.makeseries_c(100)'
10000 loops, best of 3: 36.2 usec per loop
brain:~/downloads alex$ python -mtimeit -s'import rep'
'rep.makeseries_d(100)'
10000 loops, best of 3: 54.4 usec per loop

So, it would seem that (at least among these few variations) I had
guessed right, this time -- the loop-unrolling is beneficial and append
is minutely better than extend. Of course, the yanking from the loopbody
of the boundmethod is also a key optimization here -- with unyanked
(more natural) versions [[i.e., calling series.append or series.extend
right in the loop body]] I measure:

brain:~/downloads alex$ python -mtimeit -s'import rep'
'rep.makeseries_a(100)'
10000 loops, best of 3: 57.3 usec per loop
brain:~/downloads alex$ python -mtimeit -s'import rep'
'rep.makeseries_b(100)'
10000 loops, best of 3: 83.5 usec per loop
brain:~/downloads alex$ python -mtimeit -s'import rep'
'rep.makeseries_c(100)'
10000 loops, best of 3: 48 usec per loop
brain:~/downloads alex$ python -mtimeit -s'import rep'
'rep.makeseries_d(100)'
10000 loops, best of 3: 68.4 usec per loop


Alex



More information about the Python-list mailing list