Python中的len和int的大小

5

所以,当某个东西的长度接近于1<<32(一个整数的大小)时,cPython(2.4)会有一些有趣的行为。

r = xrange(1<<30)
assert len(r) == 1<<30

内容不错,但是:

r = xrange(1<<32)
assert len(r) == 1<<32
ValueError: xrange object size cannot be reported`__len__() should return 0 <= outcome

Alex的wowrange也有这种行为。 wowrange(1<<32).l没问题,但是len(wowrange(1<<32))有问题。我猜测这里发生了一些浮点行为(被读作负数)。

  1. 这里到底发生了什么?(下面已经解决了这个问题!)
  2. 我该如何解决它? 长整型?

(我的具体应用是random.sample(xrange(1<<32),ABUNCH)),如果有人想直接解决这个问题!)


@Gregg,有趣的是,我得到了OverflowError而不是ValueError(就像Q中被接受的A一样),但这个问题微不足道。问题是,对于您的特定应用程序,您希望使用一个不能适应内存的random.sample--但每个Python结构体必须适应内存。如果您打开另一个问题并更详细地指定参数,也许可以为特定应用程序提供帮助... - Alex Martelli
@Alex,实际上,示例不必适合内存,但在2.4(我知道,旧闻!)的random模块中,它执行了一个len()调用,导致失败!xrange(1<<32)本身没问题,但是在该模块的第299行进行的调用:n = len(population)是有问题的。 - Gregg Lind
在Python 2.5、2.6、3.0和3.1中,random.sample需要调用len(),而且在每个版本中都会在xrange(1<<32)上失败(因为len()仅适用于“适合内存”的容器,而xrange在概念上并不适用)。因此,如果您能更好地说明您需要什么,特别是ABUNCH的典型值是多少,我们可以建议如何解决random.sample的这个限制(这适用于所有Python版本!)。 在我看来,最好在另一个问题中进行。 - Alex Martelli
@Alex,我打算把random.sample方法的核心代码拿出来,自己写一个,因为这很简单。 - Gregg Lind
当然,如果ABUNCH非常大,那么在性能方面需要采取一些预防措施。 - Alex Martelli
3个回答

12

cPython假设列表适合内存。这也适用于表现为列表的对象,例如xrange。 实质上,len函数期望__len__方法返回可转换为size_t的内容。如果逻辑元素的数量太大,即使这些元素实际上不存在于内存中,也无法发生转换。


感谢您解释为什么len表现出这种行为。cPython的len期望size_t - Gregg Lind
小问题:仅仅因为一个长度太大了,超出了 size_t 的范围,并不意味着这个对象就不能放入内存中。例如,我有一个类表示位字段,在 32 位的 Python 中,如果对象超过 256MB,__len__ 就会停止工作。 - Scott Griffiths

5
你会发现,
xrange(1 << 31 - 1)

最后一个表现符合你的期望。这是因为最大的有符号(32位)整数是2^31-1。

1 << 32不是正的有符号32位整数(Python的int数据类型),所以你会得到那个错误。

在Python 2.6中,我甚至不能执行xrange(1 << 32)xrange(1 << 31)而不出错,更别提对结果使用len了。

编辑如果你想要更多细节...

1 << 31表示数字0x80000000,在二进制补码表示中是32位int的最低可表示负数(-1 * 2^31)。所以,由于你正在使用的数字的按位表示,它实际上变成了负数。

对于32位二进制补码数,0x7FFFFFFF是在“溢出”进入负数之前可以表示的最高可表示整数(2^31 - 1)。

如果您感兴趣,可以阅读更多内容

请注意,当你看到类似于2147483648L的东西时,“L”表示它现在被表示为“长整数”(通常是64位,我不能保证Python如何处理它,因为我还没有阅读相关资料)。


1
尝试运行hex(1 << 32),看看会得到什么结果。提示:不是0x80000000。 - Mark Byers

1

1<<32,当作为有符号整数处理时,是负数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接