`xrange(2**100)` - > OverflowError:long int太大而无法转换为int

jfs*_*jfs 16 python range biginteger xrange python-3.x

xrange 函数不适用于大整数:

>>> 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
Run Code Online (Sandbox Code Playgroud)

Python 3.x:

>>> N = 10**100
>>> r = range(N)
>>> r = range(N, N+10)
>>> len(r)
10
Run Code Online (Sandbox Code Playgroud)

range()Python 2.x 有py3k内置函数的后端吗?

编辑

我正在寻找一个完整的"懒惰"实现range(),而不只是部分实现它的一些功能.

Ale*_*lli 19

我相信没有backport(毕竟Py 3完全消除了int/long的区别,但是在2.*它在这里留下来;-)但是不难破解你自己的,例如......:

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
Run Code Online (Sandbox Code Playgroud)

编辑出现(在PY 3 x范围的正常宗旨,范围)OP不只是要循环,而且也lenin运营商(后者则上述发电机的工作,但慢慢地-优化是可能的).对于这样的丰富性,一个班级更好......:

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
Run Code Online (Sandbox Code Playgroud)

如果这里有潜伏或类似的故障,我不会感到惊讶,但是,我希望这会有所帮助!

再次编辑:我看到索引也是必需的.编写自己的文章太难了__getitem__吗?我想是的,所以在这里它也是,在银盘上供应......:

 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
Run Code Online (Sandbox Code Playgroud)

我不知道3.0是否range支持切片(xrange在最近的2.*版本中没有 - 它曾经使用过,但由于复杂性是荒谬的并且容易出现错误而被删除),但我想我必须在沙子中绘制一条线在某个地方,所以我不打算添加它;-).


Ant*_*wns 11

好的,这是一个更全面的重新实现.

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
Run Code Online (Sandbox Code Playgroud)

还有一些测试:

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])
Run Code Online (Sandbox Code Playgroud)


Ant*_*wns 9

来自文档:

注意

xrange()旨在简单快速.实现可能会对此实施限制.Python的C实现将所有参数限制为本机C long("短"Python整数),并且还要求元素的数量适合本机C long.如果需要更大的范围,可以使用itertools模块制作备用版本:islice(count(start,step),(stop-start + step-1)// step).

或者使用生成器重新实现xrange:

def myxrange(a1, a2=None, step=1):
    if a2 is None:
        start, last = 0, a1
    else:
        start, last = a1, a2
    while cmp(start, last) == cmp(0, step):
        yield start
        start += step
Run Code Online (Sandbox Code Playgroud)

N = 10**100
len(list(myxrange(N, N+10)))
Run Code Online (Sandbox Code Playgroud)