1

我熟悉 和 之间的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)
>>> 
4

3 回答 3

4

rangeor的停止值xrange总是排他的。

引用文档(Python 2):

如果step为正,则最后一个元素最大start + i * step 小于 stop; 如果为负数,则最后一个元素是大于step的最小元素。start + i * step stop

对于Python 3

对于正数step,范围 r 的内容由公式r[i] = start + step*iwherei >= 0和确定r[i] < stop

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


关于您的问题的第二repr()部分xrange

xrange(1, 10, 4)并且xrange(1, 13, 4)是相同的,repr()对于原生 python 对象,通常返回有效的 python 代码来重新创建对象。这不需要与最初创建对象的 python 代码完全相同。

于 2013-03-14T12:49:45.247 回答
3

xrange(1, 10, 4)相当于xrange(1, 13, 4)。要使用您的示例:

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

xrange在 Python 2 中规范化了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

于 2013-03-14T13:00:41.733 回答
2

真的有关系吗?

效果是一样的。10 和 11 都不包含在 的输出中xrange()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输出中。

于 2013-03-14T12:56:41.273 回答