# Fun with fancy slicing

Discussion in 'Python' started by Dave Benjamin, Sep 30, 2003.

1. ### Dave BenjaminGuest

Hey all,

I just realized you can very easily implement a sequence grouping function
using Python 2.3's fancy slicing support:

def group(values, size):
return map(None, *[values[i::size] for i in range(size)])

>>> group(range(20), 4)

[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14, 15),
(16, 17, 18, 19)]

>>> group(range(14), 3)

[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)]

I had to use map(None, *...) instead of zip(*...) to transpose the result
because zip throws away the "orphans" at the end. Anyway, this is a useful
function to have in your toolkit if you need to do pagination or
multi-column display, among other things...

Anyone have any other interesting applications of the extended slice syntax?

Peace,
Dave

--
..:[ dave benjamin (ramenboy) -:- www.ramenfest.com -:- www.3dex.com ]:.
: d r i n k i n g l i f e o u t o f t h e c o n t a i n e r :

Dave Benjamin, Sep 30, 2003

2. ### Michael HudsonGuest

Dave Benjamin <> writes:

> Anyone have any other interesting applications of the extended slice syntax?

You can use it in a sieve prime finder (ooh, thread crossing :

/>> def sieve(p):
|.. candidates = range(p)
|.. for i in candidates[2:]:
|.. if not candidates: continue
|.. n = len(candidates[2*i::i])
|.. candidates[2*i::i] = [0]*n
|.. return filter(None, candidates[2:])
\__
->> sieve(50)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

but it's not especially efficient (in speed or memory). Quite cute,
though.

Cheers,
mwh

--
A typical luser can perform truly superhuman feats of strength &
dexterity to avoid reading documentation. -- Lionel, asr

Michael Hudson, Sep 30, 2003

3. ### Dave BenjaminGuest

In article <>, Michael Hudson wrote:
> Dave Benjamin <> writes:
>
>> Anyone have any other interesting applications of the extended slice syntax?

>
> You can use it in a sieve prime finder (ooh, thread crossing :
> ...
> but it's not especially efficient (in speed or memory). Quite cute,
> though.

But quite expressive! I'm amazed at how small that code was. It reminds me
of the trademark quicksort implementation in Haskell, ie. it may not be
great in practice, but you can see the algorithm at a high level which makes
it easier to figure out what's going on.

Anyway, thanks. That was cool. =)

Peace,
Dave

--
..:[ dave benjamin (ramenboy) -:- www.ramenfest.com -:- www.3dex.com ]:.
: d r i n k i n g l i f e o u t o f t h e c o n t a i n e r :

Dave Benjamin, Oct 1, 2003
4. ### Gerrit HollGuest

Missing messagen (Was: Re: Fun with fancy slicing)

Dave Benjamin wrote:
> In article <>, Michael Hudson wrote:
> > Dave Benjamin <> writes:
> >
> >> Anyone have any other interesting applications of the extended slice syntax?

> >
> > You can use it in a sieve prime finder (ooh, thread crossing :
> > ...
> > but it's not especially efficient (in speed or memory). Quite cute,
> > though.

I do not seem to have received this message from Michael Hudson through
python-list. I am able to locate it on the newsgroup. Does anyone else
have this problem?

Gerrit Holl.

--
278. If any one buy a male or female slave, and before a month has
elapsed the benu-disease be developed, he shall return the slave to the
-- 1780 BC, Hammurabi, Code of Law
--
Asperger Syndroom - een persoonlijke benadering:
http://people.nl.linux.org/~gerrit/
Het zijn tijden om je zelf met politiek te bemoeien:
http://www.sp.nl/

Gerrit Holl, Oct 1, 2003
5. ### Alex MartelliGuest

Dave Benjamin wrote:
...
> of the trademark quicksort implementation in Haskell, ie. it may not be
> great in practice, but you can see the algorithm at a high level which
> makes it easier to figure out what's going on.

Hmmm, you mean as in...:

def quicksort(alist):
return quicksort([ x in alist[1:] if x<=head ]) + [

....?

Alex

Alex Martelli, Oct 1, 2003
6. ### David EppsteinGuest

In article <ueEeb.206007\$>,
Alex Martelli <> wrote:

> Dave Benjamin wrote:
> ...
> > of the trademark quicksort implementation in Haskell, ie. it may not be
> > great in practice, but you can see the algorithm at a high level which
> > makes it easier to figure out what's going on.

>
> Hmmm, you mean as in...:
>
> def quicksort(alist):
> return quicksort([ x in alist[1:] if x<=head ]) + [
>
> ...?

Well, except that it gets a syntax error. And if you correct the syntax
it gets an IndexError due to the lack of a base case for the recursion.
And if you correct that, it still doesn't work correctly for lists with
repeated items.

def quicksort(L):
if len(L) < 2: return L
return quicksort([x for x in L if x < L[0]]) + \
[x for x in L if x == L[0]] + \
quicksort([x for x in L if x > L[0]])

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science

David Eppstein, Oct 1, 2003
7. ### Alex MartelliGuest

David Eppstein wrote:
...
>> def quicksort(alist):
>> return quicksort([ x in alist[1:] if x<=head ]) + [

>
> Well, except that it gets a syntax error. And if you correct the syntax
> it gets an IndexError due to the lack of a base case for the recursion.

Right on both counts -- sorry.

> And if you correct that, it still doesn't work correctly for lists with
> repeated items.

Why not? Having fixed the syntax and added the base-case, I see:

[alex@lancelot perex]\$ python -i se.py
>>> import random
>>> x=4*range(5)
>>> random.shuffle(x)
>>> x

[4, 4, 3, 1, 1, 1, 1, 2, 0, 0, 3, 4, 3, 4, 2, 0, 3, 0, 2, 2]
>>> quicksort(x)

[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]
>>>

So what am I missing? Please show a case of "list with repeated
items" where the fixed quicksort "doesn't work correctly", thanks.

btw, my favourite fixed version is:

def quicksort(alist):
except IndexError: return alist
return quicksort([ x for x in alist[1:] if x<=head ]) + [
head ] + quicksort([ x for x in alist[1:] if x>head ])

but I do see that testing len(alist) is probably better.

How sweet it would be to be able to unpack by coding:
....

Alex

Alex Martelli, Oct 2, 2003
8. ### David EppsteinGuest

In article <xdJeb.208403\$>,
Alex Martelli <> wrote:

> David Eppstein wrote:
> ...
> >> def quicksort(alist):
> >> return quicksort([ x in alist[1:] if x<=head ]) + [
> >> head ] + quicksort([ x in alist[1:] if x>head ])

> >
> > Well, except that it gets a syntax error. And if you correct the syntax
> > it gets an IndexError due to the lack of a base case for the recursion.

>
> Right on both counts -- sorry.
>
> > And if you correct that, it still doesn't work correctly for lists with
> > repeated items.

>
> Why not? Having fixed the syntax and added the base-case, I see:

Sorry, does work correctly, just not efficiently. I didn't see the = in
the first recursive call. But if you call your quicksort on say [0]*n,
each call will split the list as unevenly as possible and you get
quadratic runtime. Of course we know that nonrandom quicksort pivoting
can be quadratic anyway (e.g. on sorted input) but this to my mind is
worse because randomization doesn't make it any better. The fact that
some textbooks (e.g. CLRS!) make this mistake doesn't excuse it either.

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science

David Eppstein, Oct 2, 2003
9. ### Damien WyartGuest

* David Eppstein <> in comp.lang.python:
> Of course we know that nonrandom quicksort pivoting can be quadratic
> anyway (e.g. on sorted input) but this to my mind is worse because
> randomization doesn't make it any better. The fact that some textbooks
> (e.g. CLRS!) make this mistake doesn't excuse it either.

Could you explain in more detail the error made in CLRS on this topic
(with a reference if possible) ? I did not precisely catch your
explanation here.

--
Damien Wyart

Damien Wyart, Oct 2, 2003
10. ### Michael HudsonGuest

Re: Missing messagen (Was: Re: Fun with fancy slicing)

Gerrit Holl <> writes:

> Dave Benjamin wrote:
> > In article <>, Michael Hudson wrote:
> > > Dave Benjamin <> writes:
> > >
> > >> Anyone have any other interesting applications of the extended slice syntax?
> > >
> > > You can use it in a sieve prime finder (ooh, thread crossing :
> > > ...
> > > but it's not especially efficient (in speed or memory). Quite cute,
> > > though.

>
> I do not seem to have received this message from Michael Hudson through
> python-list. I am able to locate it on the newsgroup. Does anyone else
> have this problem?

Hmm, I saw it

I don't really read the newsgroup closely enough any more to know if
any messages are going missing, I'm afraid.

Cheers,
mwh

--
Screaming 14-year-old boys attempting to prove to each other that
they are more 3133t than j00.
-- Reason #8 for quitting slashdot today, from
http://www.cs.washington.edu/homes/klee/misc/slashdot.html

Michael Hudson, Oct 2, 2003
11. ### David EppsteinGuest

In article <3f7bf423\$0\$20654\$>,
Damien Wyart <> wrote:

> * David Eppstein <> in comp.lang.python:
> > Of course we know that nonrandom quicksort pivoting can be quadratic
> > anyway (e.g. on sorted input) but this to my mind is worse because
> > randomization doesn't make it any better. The fact that some textbooks
> > (e.g. CLRS!) make this mistake doesn't excuse it either.

>
> Could you explain in more detail the error made in CLRS on this topic
> (with a reference if possible) ? I did not precisely catch your
> explanation here.
>

CLRS' partition routine ends up partitioning an n-item array into the
items <= the pivot, the pivot itself, and the items > the pivot.
If the items are all equal, that means that the first part gets n-1
items and the last part gets nothing, regardless of which item you
select as pivot. If you analyze the algorithm on this input, you get
the recurrence T(n)=O(n)+T(n-1)+T(0) which solves to O(n^2).

Throughout most of the quicksort chapter, CLRS at least include
exercises mentioning the case of all equal inputs, asking what happens
for those inputs, and in one exercise suggesting a partition routine
that might partition those inputs more equally (but who knows what it
should do when merely most of the inputs are equal...) However in the
randomized quicksort section they ignored this complication and seemed
to be claiming that their randomized quicksort has O(n log n) expected
time, unconditionally.

This problem was finally corrected in the fourth printing of the second
edition; see the errata at
<http://www.cs.dartmouth.edu/~thc/clrs-2e-bugs/bugs.php>
for more details.

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science

David Eppstein, Oct 2, 2003
12. ### David C. FoxGuest

Re: *-unpacking (Re: Fun with fancy slicing)

Greg Ewing (using news.cis.dfn.de) wrote:
> Alex Martelli wrote:
>
>> How sweet it would be to be able to unpack by coding:

>
>
> Indeed! I came across another use case for this
> recently, as well. I was trying to parse some
> command strings of the form
>
> command arg arg ...
>
> where some commands had args and some didn't.
> I wanted to split the command off the front
> and keep the args for later processing once
> I'd decoded the command. My first attempt
> went something like
>
> command, args = cmdstring.split(" ", maxsplit = 1)
>
> but this fails when there are no arguments,
> because the returned list has only one element
> in that case.
>
> It would have been very nice to be able to
> simply say
>
> command, *args = cmdstring.split()
>
> and get the command as a string and a
> list of 0 or more argument strings.
>
>

In the mean time, it isn't too hard to write a function which does this:

def first_rest(x):
return x[0], x[1:]

command, args = first_rest(cmdstring.split())

or, in one step

def chop_word(s):
return first_rest(s.split())

command, args = chop_word(cmdstring)

David

David C. Fox, Oct 3, 2003
13. ### Lulu of the Lotus-EatersGuest

Re: *-unpacking

|Alex Martelli wrote:
|> How sweet it would be to be able to unpack by coding:

"Greg Ewing (using news.cis.dfn.de)" <> wrote previously:
| command arg arg ...
| command, *args = cmdstring.split()
|and get the command as a string and a list of 0 or more argument strings.

I think I've written on this list before that I would like this
too--Ruby does this, IIRC. If anyone writes a PEP, you have my +1 in

For Greg's particular case, one approach that doesn't look too bad is:

command = args.pop(0)
# ... do stuff ...
try:
more = args.pop(0)
except IndexError:
# no more

For a really long list, it would be faster to do an 'args.reverse()' up
front, and '.pop()' off the end (Greg and Alex know all this, of course).

Yours, Lulu...

--
mertz@ _/_/_/_/ THIS MESSAGE WAS BROUGHT TO YOU BY: \_\_\_\_ n o
gnosis _/_/ Postmodern Enterprises \_\_
..cx _/_/ \_\_ d o
_/_/_/ IN A WORLD W/O WALLS, THERE WOULD BE NO GATES \_\_\_ z e

Lulu of the Lotus-Eaters, Oct 3, 2003
14. ### Greg Ewing (using news.cis.dfn.de)Guest

*-unpacking (Re: Fun with fancy slicing)

Alex Martelli wrote:
> How sweet it would be to be able to unpack by coding:

Indeed! I came across another use case for this
recently, as well. I was trying to parse some
command strings of the form

command arg arg ...

where some commands had args and some didn't.
I wanted to split the command off the front
and keep the args for later processing once
I'd decoded the command. My first attempt
went something like

command, args = cmdstring.split(" ", maxsplit = 1)

but this fails when there are no arguments,
because the returned list has only one element
in that case.

It would have been very nice to be able to
simply say

command, *args = cmdstring.split()

and get the command as a string and a
list of 0 or more argument strings.

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Greg Ewing (using news.cis.dfn.de), Oct 3, 2003
15. ### David EppsteinGuest

Re: *-unpacking (Re: Fun with fancy slicing)

In article <Jd7fb.484435\$cF.170532@rwcrnsc53>,
"David C. Fox" <> wrote:

> In the mean time, it isn't too hard to write a function which does this:
>
> def first_rest(x):
> return x[0], x[1:]

Shouldn't that be called cons?

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science

David Eppstein, Oct 3, 2003
16. ### Alex MartelliGuest

Re: *-unpacking (Re: Fun with fancy slicing)

David Eppstein wrote:

>> In the mean time, it isn't too hard to write a function which does this:
>>
>> def first_rest(x):
>> return x[0], x[1:]

>
> Shouldn't that be called cons?

Hmmm, feels more like the 'reverse' of a cons to me -- takes a list
and gives me the car and cdr...

Alex

Alex Martelli, Oct 3, 2003
17. ### Alex MartelliGuest

Re: *-unpacking

Lulu of the Lotus-Eaters wrote:
...
> |> head, *tail = alist
>
> "Greg Ewing (using news.cis.dfn.de)" <> wrote
> previously:
> | command arg arg ...
> | command, *args = cmdstring.split()
> |and get the command as a string and a list of 0 or more argument strings.
>
> I think I've written on this list before that I would like this
> too--Ruby does this, IIRC. If anyone writes a PEP, you have my +1 in
>
> For Greg's particular case, one approach that doesn't look too bad is:
>
> command = args.pop(0)
> # ... do stuff ...
> try:
> more = args.pop(0)
> except IndexError:
> # no more

I'm not sure what this 'more' is about, actually. Greg's case is
currently best solved [IMHO] with
args = cmdstring.split()
command = args.pop(0)

> For a really long list, it would be faster to do an 'args.reverse()' up
> front, and '.pop()' off the end (Greg and Alex know all this, of course).

Actually, I don't -- both args.reverse() and args.pop(0) are O(len(args)),
so I don't know their relative speeds offhand. Interestingly enough,
timeit.py, for once, doesn't want to let me know about them either...:

[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags.pop(0)'
Traceback (most recent call last):
File "timeit.py", line 249, in main
x = t.timeit(number)
File "timeit.py", line 158, in timeit
return self.inner(it, self.timer)
File "<timeit-src>", line 6, in inner
x=ags.pop(0)
IndexError: pop from empty list
[alex@lancelot python2.3]\$

....since each .pop is modifying the ags list, the once-only setup
statement doesn't suffice... OK, so we need to repeat (and thus,
alas, intrinsically measure) the list copying too (sigh):

[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24.5 usec per loop

[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'ags.reverse(); x=ags[:].pop()'
10000 loops, best of 3: 23.2 usec per loop

the results of the two snippets aren't identical, but that should
not affect the timing measured (as the use of ags[:] and the
repetition are time-measurement artefacts anyway). So, it does
look like reversing first IS faster -- by a hair. Trying to
remove the ags[:] part / overhead gave me a shock, though...:

[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)' 'x=ags[:]'
10000 loops, best of 3: 35.2 usec per loop

So -- it's clear to me that I do NOT understand what's going on
here. If just the ags[:] is 35.2 usec, how can the ags[:].pop(0)
be 24.5 ... ???

Alex

Alex Martelli, Oct 3, 2003
18. ### Michael HudsonGuest

Re: *-unpacking

Alex Martelli <> writes:

> So -- it's clear to me that I do NOT understand what's going on
> here. If just the ags[:] is 35.2 usec, how can the ags[:].pop(0)
> be 24.5 ... ???

How quiet was your machine when you ran the tests? I see behaviour
more in line with what you'd expect:

[mwh@pc150 build]\$ ./python ../Lib/timeit.py -s'ags=range(1000)' 'x=ags[:]'
10000 loops, best of 3: 31.6 usec per loop
[mwh@pc150 build]\$ ./python ../Lib/timeit.py -s'ags=range(1000)' 'x=ags[:].pop(0)'
10000 loops, best of 3: 39.8 usec per loop

Cheers,
mwh

--
About the use of language: it is impossible to sharpen a
pencil with a blunt axe. It is equally vain to try to do
it with ten blunt axes instead.
-- E.W.Dijkstra, 18th June 1975. Perl did not exist at the time.

Michael Hudson, Oct 3, 2003
19. ### David EppsteinGuest

Re: *-unpacking (Re: Fun with fancy slicing)

In article <22cfb.159311\$>,
Alex Martelli <> wrote:

> David Eppstein wrote:
>
> >> In the mean time, it isn't too hard to write a function which does this:
> >>
> >> def first_rest(x):
> >> return x[0], x[1:]

> >
> > Shouldn't that be called cons?

>
> Hmmm, feels more like the 'reverse' of a cons to me -- takes a list
> and gives me the car and cdr...

Well, but it returns an object composed of a car and a cdr, which is
exactly what a cons is...

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science

David Eppstein, Oct 3, 2003
20. ### Alex MartelliGuest

Re: *-unpacking

Michael Hudson wrote:

> Alex Martelli <> writes:
>
>> So -- it's clear to me that I do NOT understand what's going on
>> here. If just the ags[:] is 35.2 usec, how can the ags[:].pop(0)
>> be 24.5 ... ???

>
> How quiet was your machine when you ran the tests? I see behaviour

Very, and the numbers were highly repeatable:

-- running just now:

[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)' 'x=ags[:]'
10000 loops, best of 3: 36.9 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)' 'x=ags[:]'
10000 loops, best of 3: 35.2 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)' 'x=ags[:]'
10000 loops, best of 3: 35.8 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)' 'x=ags[:]'
10000 loops, best of 3: 35.6 usec per loop

-- and from a copy & paste of the screen as of a while ago:

[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24.5 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24.5 usec per loop

-- _however_ -- retrying the latter now:

[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 48.8 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 46.1 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 46.5 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24.5 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24.4 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24.5 usec per loop

-- _SO_ -- immediately going back to the just-copy tests...:

[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)' 'x=ags[:]'
100000 loops, best of 3: 19.3 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)' 'x=ags[:]'
100000 loops, best of 3: 19.3 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -s'ags=range(1000)' 'x=ags[:]'
100000 loops, best of 3: 19.3 usec per loop

SO -- so much for the "quiet"... clearly there _IS_ something periodically
running and distorting the elapsed-time measurements (which are the default
here on Linux) by a hefty factor of 2. So much for this kind of casual
benchmarking...!-) I guess I've been doing a little too much of it...

> more in line with what you'd expect:
>
> [mwh@pc150 build]\$ ./python ../Lib/timeit.py -s'ags=range(1000)'
> ['x=ags[:]'
> 10000 loops, best of 3: 31.6 usec per loop
> [mwh@pc150 build]\$ ./python ../Lib/timeit.py -s'ags=range(1000)'
> ['x=ags[:].pop(0)'
> 10000 loops, best of 3: 39.8 usec per loop

Yep, makes more sense. So, moving to the more-stable -c (CPU time,
as given by time.clock):

[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'x=ags[:]'
100000 loops, best of 3: 19.2 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'x=ags[:]'
100000 loops, best of 3: 19.2 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'x=ags[:]'
100000 loops, best of 3: 19.2 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 24 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'x=ags[:].pop(0)'
10000 loops, best of 3: 23 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'ags.reverse(); x=ags[:].pop()'
10000 loops, best of 3: 23 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'ags.reverse(); x=ags[:].pop()'
10000 loops, best of 3: 22 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'ags.reverse(); x=ags[:].pop()'
10000 loops, best of 3: 23 usec per loop
[alex@lancelot python2.3]\$ python timeit.py -c -s'ags=range(1000)'
'ags.reverse(); x=ags[:].pop()'
10000 loops, best of 3: 23 usec per loop

it WOULD seem to be confirmed that reverse-then-pop() is VERY
slightly faster than pop(0) -- 22/23 instead of 23/24 usec for
a 1000-long list... of which 19.2 are the apparently-repeatable
overhead of copying that list. I still wouldn't say that I
"KNOW" this, though -- the margin is SO tiny and uncertain...!!!

It seems to scale up linearly going from 1000 to 5000: just
the copy, 105-108; ags[:].pop(0), 120-123; reverse then pop,
116-117. This is always with the -c (once burned...).

Alex

Alex Martelli, Oct 3, 2003