why I don't like range/xrange

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Fri Feb 16 11:17:29 EST 2007


On Fri, 16 Feb 2007 07:30:15 -0800, stdazi wrote:

> Hello!
> 
> Many times I was suggested to use xrange and range instead of the
> while constructs, and indeed, they are quite more elegant - but, after
> calculating the overhead (and losen flexibility) when working with
> range/xrange, and while loops, you get to the conclusion that it isn't
> really worth using range/xrange loops.

I prefer to _measure_ the overhead instead of guessing.

import timeit
whileloop = """i = 0
while i < N:
    i += 1
    pass
"""
forloop = """for i in xrange(N):
    pass
"""

Now let's see how fast the loops are.

>>> timeit.Timer(whileloop, "N = 10000").repeat(3, 1000)
[3.5716907978057861, 3.5263650417327881, 3.5975079536437988]
>>> timeit.Timer(forloop, "N = 10000").repeat(3, 1000)
[1.3608510494232178, 1.341961145401001, 1.3180010318756104]

Looks to me that a for loop using xrange is more than twice as fast as a
while loop. The advantage is about the same for small N:

>>> timeit.Timer(whileloop, "N = 100").repeat(3, 1000)
[0.052264213562011719, 0.049374103546142578, 0.041945934295654297]
>>> timeit.Timer(forloop, "N = 100").repeat(3, 1000)
[0.012259006500244141, 0.013512134552001953, 0.015196800231933594]


What makes you think that a while loop has less overhead?



> I'd like to show some examples and I'll be glad if someone can suggest
> some other fixes than while a loop :-)
> 
> a) range overfllow :
> 
> 
> for i in range(0, 1 << len(S)) :
> .....
> OverflowError: range() result has too many items
> 
> ok, so we fix this one with xrange !


By the way, you don't need to write range(0, N). You can just write
range(N).

Yes, you're correct, range(some_enormous_number) will fail if
some_enormous_number is too big.



> b) xrange long int overflow :
> 
> for i in xrange(0, 1 << len(S)) :
> ........
> OverflowError: long int too large to convert to int


Are you really doing something at least 2147483647 times? I'm guessing
that you would be better off rethinking your algorithm.



> Next thing I miss is the flexibility as in C for loops :
> 
> for (i = 0; some_function() /* or other condition */ ; i++)

This would be written in Python as:

i = 0
while some_function():
    i += 1

A more flexible way would be to re-write some_function() as an iterator,
then use it directly:

for item in some_function():
    # do something with item


 
> or,
> 
> for (i = 0 ; i < 10 ; i++)
>    i = 10;


This would be written in Python as:

for i in xrange(10):
    i = 10



> I don't think range/xrange sucks, but I really think there should be
> some other constructs to improve the looping flexibility.

Every loop can be turned into a while loop. If you have while, you don't
_need_ anything else.

But for elegance and ease of use, a small number of looping constructs is
good. Python has:

while condition:
    block
else:
    # runs if while exits *without* hitting break statement
    block


for item in any_sequence:
    block
else:
    # runs if for exits *without* hitting break statement
    block


Nice, clean syntax.

any_sequence isn't limited to mere arithmetic sequences -- it can be any
sequence of any objects. But if you need a C-style for loop, using
integers, range/xrange([start, ] stop [, step]) is provided.


-- 
Steven.




More information about the Python-list mailing list