我熟悉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)
>>>
答案 0 :(得分:3)
range
或xrange
的停止值始终为独占。
引自docs(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
关于repr()
xrange
的问题的第二部分:
xrange(1, 10, 4)
和xrange(1, 13, 4)
相同,本地python对象的repr()
通常会返回有效的python代码来重新创建对象。这不需要是最初创建对象的完全相同的python代码。
答案 1 :(得分:2)
真的重要吗?
效果是一样的。 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
输出中。
答案 2 :(得分:2)
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