Slicing versus loops, was Re: for i in range() anti-pattern

Peter Otten __peter__ at web.de
Thu Nov 30 05:17:17 EST 2006


Steven D'Aprano wrote:

> And remember that if alist is truly huge, you may take a performance hit
> due to duplicating all those megabytes of data when you slice it. 

Having the same object in two lists simultaneously does not double the total
amount of memory; you just need space for an extra pointer.

> If you 
> are modifying the original, better to skip making a slice.
> 
> I wrote a piece of code the other day that had to walk along a list,
> swapping adjacent elements like this:
> 
> for i in xrange(0, len(alist)-1, 2):
>     alist[i], alist[i+1] = alist[i+1], alist[i]
> 
> 
> The version using enumerate is no improvement:
> 
> for i, x in enumerate(alist[0:len(alist)-1:2]):
>     alist[i*2], alist[i*2+1] = alist[i*2+1], x
> 
> 
> In my opinion, it actually is harder to understand what it is doing.
> Swapping two items using "a,b = b,a" is a well known and easily recognised
> idiom. Swapping two items using "a,b = b,c" is not.

That example was chosen to prove your point. The real contender for the
"swap items" problem are slices. 

def swap_slice(items):
    left = items[::2]
    items[::2] = items[1::2]
    items[1::2] = left
    return items

def swap_loop(items):
    for i in xrange(0, len(items)-1, 2):
        k = i+1
        items[i], items[k] = items[k], items[i]
    return items

$ python2.5 -m timeit -s 'from swap import swap_loop as swap; r =
range(10**6)' 'swap(r)'
10 loops, best of 3: 326 msec per loop
$ python2.5 -m timeit -s 'from swap import swap_slice as swap; r =
range(10**6)' 'swap(r)'
10 loops, best of 3: 186 msec per loop

$ python2.5 -m timeit -s 'from swap import swap_loop as swap; r =
range(10**7)' 'swap(r)'
10 loops, best of 3: 3.27 sec per loop
$ python2.5 -m timeit -s 'from swap import swap_slice as swap; r =
range(10**7)' 'swap(r)'
10 loops, best of 3: 2.29 sec per loop

With 10**7 items in the list I hear disc access on my system, so the
theoretical sweet spot where swap_slice() is already swapping while
swap_loop() is not may be nonexistent...

Peter




More information about the Python-list mailing list