简体   繁体   English

Python 2中奇怪的xrange()行为

[英]strange xrange() behavior in Python 2

I am familiar with the difference between range() and xrange() . 我熟悉range()xrange()之间的区别。 I noticed something weird with xrange() : 我注意到xrange()很奇怪:

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

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

Functionally, it is correct: 从功能上讲,这是正确的:

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

However, as you can see, the stop value in the returned xrange object is the next higher value after the last legal value. 但是,如您所见,返回的xrange对象中的停止值是最后一个合法值之后的下一个更高的值。 Any reason why? 有什么原因吗?

range() which now provides the same functionality in Python 3 as xrange in Python 2 behaves as expected: range()现在在Python 3中提供了与Python 2中的xrange相同的功能:

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

The stop value of a range or xrange is always exclusive. rangexrange的终止值始终是唯一的。

Quote from the docs (Python 2): 引用文档 (Python 2):

If step is positive, the last element is the largest start + i * step less than stop ; 如果step为正,则最后一个元素为最大start + i * step 小于 stop if step is negative, the last element is the smallest start + i * step greater than stop . 如果step是否定的,最后一个元素是最小的start + i * step 大于 stop

And for Python 3 : 对于Python 3

For a positive step , the contents of a range r are determined by the formula r[i] = start + step*i where i >= 0 and r[i] < stop . 对于正step ,范围r的内容由下式确定r[i] = start + step*i ,其中i >= 0r[i] < stop

For a negative step , the contents of the range are still determined by the formula r[i] = start + step*i , but the constraints are i >= 0 and r[i] > stop . 对于负step ,范围的内容仍由公式r[i] = start + step*i ,但约束条件为i >= 0r[i] > stop


About the second part of your question regarding the repr() of the xrange : 关于有关xrangerepr()的问题的第二部分:

xrange(1, 10, 4) and xrange(1, 13, 4) are identical and repr() for native python objects usually returns valid python code to recreate the object. xrange(1, 10, 4) xrange(1, 13, 4) xrange(1, 10, 4)xrange(1, 13, 4)相同,并且本机python对象的repr()通常返回有效的python代码以重新创建该对象。 This does not need to be the exactly same python code that initially created the object. 这不必是最初创建该对象的完全相同的python代码。

Does it really matter? 真的有关系吗?

The effect is the same. 效果是一样的。 Neither 10 nor 11 is included in the output of xrange() , and xrange(1, 11, 2) is equivalent to xrange(1, 10, 2) . xrange()的输出中既不包含10也不包含11,并且xrange(1, 11, 2) 等效xrange(1, 10, 2)

The Python 2 range type (the result of xrange() ) stores the range length, not the end value, so to create the repr output it calculates that end value for you. Python 2范围类型( xrange()的结果)存储范围长度,而不是最终值,因此要创建repr输出,它将为您计算该最终值。 And because you used a step value, the calculation shows the result of the formula start + length * step . 并且由于使用了步长值,因此计算将显示公式start + length * step For the implementation, the length is the more important value, the end value can safely be discarded and recalculated as needed. 对于实现,长度是更重要的值,可以安全地舍弃end值,并根据需要重新计算。

So, when you create xrange(1, 10, 2) , it calculates the range length and stores that instead of the end value: 因此,当您创建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;

The Python 3 Range object stores the end value in addition to the length, so you can query the object for it and display it in the repr output. 除了长度,Python 3 Range对象还存储最终值,因此您可以查询该对象并将其显示在repr输出中。

xrange(1, 10, 4) is equivalent to xrange(1, 13, 4) . xrange(1, 10, 4)等效于xrange(1, 13, 4) To use your example: 使用您的示例:

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

xrange in Python 2 canonicalizes the start, stop, step arguments. Python 2中的xrange规范化了start, stop, step参数。 Internally, the xrange implementation stores the triple start, step and length (number of elements in the xrange object) instead of start, step and stop. 在内部, xrange实现存储三重开始,步长和长度( xrange对象中的元素数),而不是开始,步进和停止。 Here is how xrange.__repr__() is implemented [1]: 这是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 [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