[英]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)
>>>
range
或xrange
的终止值始终是唯一的。
引用文档 (Python 2):
如果
step
为正,则最后一个元素为最大start + i * step
小于stop
; 如果step
是否定的,最后一个元素是最小的start + i * step
大于stop
。
对于Python 3 :
对于正
step
,范围r的内容由下式确定r[i] = start + step*i
,其中i >= 0
和r[i] < stop
。对于负
step
,范围的内容仍由公式r[i] = start + step*i
,但约束条件为i >= 0
且r[i] > stop
。
关于有关xrange
的repr()
的问题的第二部分:
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.