Search code examples
pythonpython-3.xrangebigintegerxrange

`xrange(2**100)` -> OverflowError: long int too large to convert to int


xrange function doesn't work for large integers:

>>> N = 10**100
>>> xrange(N)
Traceback (most recent call last):
...
OverflowError: long int too large to convert to int
>>> xrange(N, N+10)
Traceback (most recent call last):
...
OverflowError: long int too large to convert to int

Python 3.x:

>>> N = 10**100
>>> r = range(N)
>>> r = range(N, N+10)
>>> len(r)
10

Is there a backport of py3k builtin range() function for Python 2.x?

Edit

I'm looking for a complete implementation of "lazy" range(), not just a partial implementation of some of its functionality.


Solution

  • Okay, here's a go at a fuller reimplementation.

    class MyXRange(object):
        def __init__(self, a1, a2=None, step=1):
            if step == 0:
                raise ValueError("arg 3 must not be 0")
            if a2 is None:
                a1, a2 = 0, a1
            if (a2 - a1) % step != 0:
                a2 += step - (a2 - a1) % step
            if cmp(a1, a2) != cmp(0, step):
                a2 = a1
            self.start, self.stop, self.step = a1, a2, step
    
        def __iter__(self):
            n = self.start
            while cmp(n, self.stop) == cmp(0, self.step):
                yield n
                n += self.step
    
        def __repr__(self):
            return "MyXRange(%d,%d,%d)" % (self.start, self.stop, self.step)
    
        # NB: len(self) will convert this to an int, and may fail
        def __len__(self):
            return (self.stop - self.start)//(self.step)
    
        def __getitem__(self, key):
            if key < 0:
                key = self.__len__() + key
                if key < 0:
                    raise IndexError("list index out of range")
                return self[key]
            n = self.start + self.step*key
            if cmp(n, self.stop) != cmp(0, self.step):
                raise IndexError("list index out of range")
            return n
    
        def __reversed__(self):
            return MyXRange(self.stop-self.step, self.start-self.step, -self.step)
    
        def __contains__(self, val):
            if val == self.start: return cmp(0, self.step) == cmp(self.start, self.stop)
            if cmp(self.start, val) != cmp(0, self.step): return False
            if cmp(val, self.stop) != cmp(0, self.step): return False
            return (val - self.start) % self.step == 0
    

    And some testing:

    def testMyXRange(testsize=10):
        def normexcept(f,args):
            try:
                r = [f(args)]
            except Exception, e:
                r = type(e)
            return r
    
        for i in range(-testsize,testsize+1):
            for j in range(-testsize,testsize+1):
                print i, j
                for k in range(-9, 10, 2):
                    r, mr = range(i,j,k), MyXRange(i,j,k)
    
                    if r != list(mr):
                        print "iter fail: %d, %d, %d" % (i,j,k)
    
                    if list(reversed(r)) != list(reversed(mr)):
                        print "reversed fail: %d, %d, %d" % (i,j,k)
    
                    if len(r) != len(mr):
                        print "len fail: %d, %d, %d" % (i,j,k)
    
                    z = [m for m in range(-testsize*2,testsize*2+1)
                          if (m in r) != (m in mr)]
                    if z != []:
                        print "contains fail: %d, %d, %d, %s" % (i,j,k,(z+["..."])[:10])
    
                    z = [m for m in range(-testsize*2, testsize*2+1) 
                          if normexcept(r.__getitem__, m) != normexcept(mr.__getitem__, m)]
                    if z != []:
                        print "getitem fail: %d, %d, %d, %s" % (i,j,k,(z+["..."])[:10])