`xrange(2**100)` -> OverflowError: long int too large to convert to int
Question: `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.


Answer: I believe there is no backport (Py 3's completely removed the int/long
distinction, after all, but in 2.* it's here to stay;-) but it's not hard to
hack your own, e.g....:

    
    
    import operator
    
    def wowrange(start, stop, step=1):
      if step == 0:
        raise ValueError('step must be != 0')
      elif step < 0:
        proceed = operator.gt
      else:
        proceed = operator.lt
      while proceed(start, stop):
        yield start
        start += step
    

**Edit** it appears the OP doesn't just want looping (the normal purpose of
xrange, and range in Py3), but also `len` and the `in` operator (the latter
does work on the above generator, but slowly -- optimizations are possible).
For such richness a class is better...:

    
    
    import operator
    
    class wowrange(object):
      def __init__(self, start, stop=None, step=1):
        if step == 0: raise ValueError('step must be != 0')
        if stop is None: start, stop = 0, start
        if step < 0:
          self.proceed = operator.gt
          self.l = (stop-start+step+1)//step
        else:
          self.proceed = operator.lt
          self.l = (stop-start+step-1)//step
        self.lo = min(start, stop)
        self.start, self.stop, self.step = start, stop, step
      def __iter__(self):
        start = self.start
        while self.proceed(start, self.stop):
          yield start
          start += self.step
      def __len__(self):
        return self.l
      def __contains__(self, x):
        if x == self.stop:
          return False
        if self.proceed(x, self.start):
          return False
        if self.proceed(self.stop, x):
          return False
        return (x-self.lo) % self.step == 0
    

I wouldn't be surprised if there's an off-by-one or similar glitch lurking
here, but, I hope this helps!

**Edit** again: I see indexing is ALSO required. Is it just too hard to write
your own `__getitem__`? I guess it is, so here it, too, is, served on a silver
plate...:

    
    
     def __getitem__(self, i):
       if i < 0:
         i += self.l
         if i < 0: raise IndexError
       elif if i >= self.l:
         raise IndexError
       return self.start + i * self.step
    

I don't know if 3.0 `range` supports slicing (`xrange` in recent `2.*`
releases doesn't -- it used to, but that was removed because the complication
was ridiculous and prone to bugs), but I guess I do have to draw a line in the
sand somewhere, so I'm not going to add it;-).

