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