繁体   English   中英

Python 2中奇怪的xrange()行为

[英]strange xrange() behavior in Python 2

我熟悉range()xrange()之间的区别。 我注意到xrange()很奇怪:

>>> xrange(1,10,2)
xrange(1, 11, 2)

>>> xrange(1,10,4)
xrange(1, 13, 4)

从功能上讲,这是正确的:

>>> for item in xrange(1,10,4):
...     print item
... 
1
5
9
>>>

但是,如您所见,返回的xrange对象中的停止值是最后一个合法值之后的下一个更高的值。 有什么原因吗?

range()现在在Python 3中提供了与Python 2中的xrange相同的功能:

>>> range(1,10,4)
range(1, 10, 4)
>>> range(1,10,2)
range(1, 10, 2)
>>> 

rangexrange的终止值始终是唯一的。

引用文档 (Python 2):

如果step为正,则最后一个元素为最大start + i * step 小于 stop 如果step是否定的,最后一个元素是最小的start + i * step 大于 stop

对于Python 3

对于正step ,范围r的内容由下式确定r[i] = start + step*i ,其中i >= 0r[i] < stop

对于负step ,范围的内容仍由公式r[i] = start + step*i ,但约束条件为i >= 0r[i] > stop


关于有关xrangerepr()的问题的第二部分:

xrange(1, 10, 4) xrange(1, 13, 4) xrange(1, 10, 4)xrange(1, 13, 4)相同,并且本机python对象的repr()通常返回有效的python代码以重新创建该对象。 这不必是最初创建该对象的完全相同的python代码。

真的有关系吗?

效果是一样的。 xrange()的输出中既不包含10也不包含11,并且xrange(1, 11, 2) 等效xrange(1, 10, 2)

Python 2范围类型( xrange()的结果)存储范围长度,而不是最终值,因此要创建repr输出,它将为您计算该最终值。 并且由于使用了步长值,因此计算将显示公式start + length * step 对于实现,长度是更重要的值,可以安全地舍弃end值,并根据需要重新计算。

因此,当您创建xrange(1, 10, 2) ,它将计算范围长度并将其存储而不是最终值:

if (step > 0 && lo < hi)
return 1UL + (hi - 1UL - lo) / step;
else if (step < 0 && lo > hi)
return 1UL + (lo - 1UL - hi) / (0UL - step);
else
return 0UL;

除了长度,Python 3 Range对象还存储最终值,因此您可以查询该对象并将其显示在repr输出中。

xrange(1, 10, 4)等效于xrange(1, 13, 4) 使用您的示例:

>>> for item in xrange(1,13,4):
...     print item
... 
1
5
9
>>> 

Python 2中的xrange规范化了start, stop, step参数。 在内部, xrange实现存储三重开始,步长和长度( xrange对象中的元素数),而不是开始,步进和停止。 这是xrange.__repr__()的实现方法[1]:

rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
                          r->start,
                          r->start + r->len * r->step,
                          r->step);

[1] https://github.com/replit/empythoned/blob/master/cpython/Objects/rangeobject.c

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM