xrange in Python

The Qualification round in Google code jam taught me a new thing about python.

Imagine following program for getting asleep:

# asleep.py
import sys, time
sheep = int(sys.argv[1:].pop())
print "Counting sheep up to", sheep
for i in xrange(sheep):
	time.sleep(1)
	if i > 4: break
	print i+1,
print "Fell asleep"

and you run it:

$ python asleep.py 1111111
Counting sheep up to 1111111
1 2 3 4 5 Fell asleep

It looks fine because xrange does not create the whole list [0, 1, ..., 1111110] but instead works as “generator” that requests the next value on demand.

But what happens if we raise the sheep count?

$ python asleep.py 11111111111
Counting sheep up to 11111111111
Traceback (most recent call last):
  File "asleep.py", line 7, in <module>
    for i in xrange(sheep):
OverflowError: Python int too large to convert to C long

That’s interesting. It turns out that when you run the line

 ###
sheep = int(sys.argv[1:].pop())
###

the type of sheep variable may vary:

 ###
sheep = int(sys.argv[1:].pop())
print sheep.__class__
###
$ python asleep.py 1111111
<type 'int'>
$ python asleep.py 11111111111
<type 'long'>

Basically, Python checks the input value and if it’s inside the range [-sys.maxint - 1, sys.maxint] it returns int, otherwise converts it to long. Same thing happens if you run a code like:

a = sys.maxint
print a.__class__ # <type 'int'>
a += 1
print a.__class__ # <type 'long'>

So simply use a while loop and you’re safe:

import sys, time
sheep = int(sys.argv[1:].pop())
print "Counting sheep up to", sheep

i = 0
while i < sheep:
    time.sleep(1)
    if i > 4: break
    print i+1,
    i+=1
print "Fell asleep"

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.