range 对象很特殊:
Python 会将 range 对象与 Sequences 进行比较。这实质上意味着比较不评估如何它们代表给定序列,而是它们代表什么。
start、stop 和 step 参数完全不同的事实在这里没有区别,因为它们在展开时都表示一个空列表:
例如第一个range对象:
list(range(0)) # []
和第二个range 对象:
list(range(2, 2, 2)) # []
两者都表示一个空列表,并且由于两个空列表比较相等 (True),所以 表示它们的 range 对象也是如此。
因此,您可以拥有完全不同的外观 range 对象;如果它们代表相同的序列,它们将比较相等:
range(1, 5, 100) == range(1, 30, 100)
两者都表示具有单个元素 [1] 的列表,因此这两个也将比较相等。
不,range 对象真的很特别:
但请注意,即使比较不评估如何它们表示一个序列,比较的结果可以实现使用单独 strong> start、step 的值以及 range 对象的 len;这对比较的速度有非常有趣的影响:
r0 = range(1, 1000000)
r1 = range(1, 1000000)
l0 = list(r0)
l1 = list(r1)
范围比较超快:
%timeit r0 == r1
The slowest run took 28.82 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 160 ns per loop
另一方面,列表..
%timeit l0 == l1
10 loops, best of 3: 27.8 ms per loop
是的..
正如 @SuperBiasedMan 所述,这仅适用于 Python 3 中的范围对象。Python 2 range() 是一个普通的 ol' 函数,它返回一个列表,而 2.x xrange对象不具备 Python 3 中 range 对象所具有的比较功能 (and not only these..)。
查看 @ajcr's answer 以获取直接来自 Python 3 range 对象的源代码的引号。那里记录了两个不同范围之间的比较实际上需要什么:简单快速的操作。 range_equals 函数在 range_richcompare function 中用于 EQ 和 NE 情况,并分配给 tp_richcompare slot for PyRange_Type types。
我相信range_equals 的实现很容易阅读(因为它很简单)添加到这里:
/* r0 and r1 are pointers to rangeobjects */
/* Check if pointers point to same object, example:
>>> r1 = r2 = range(0, 10)
>>> r1 == r2
obviously returns True. */
if (r0 == r1)
return 1;
/* Compare the length of the ranges, if they are equal
the checks continue. If they are not, False is returned. */
cmp_result = PyObject_RichCompareBool(r0->length, r1->length, Py_EQ);
/* Return False or error to the caller
>>> range(0, 10) == range(0, 10, 2)
fails here */
if (cmp_result != 1)
return cmp_result;
/* See if the range has a lenght (non-empty). If the length is 0
then due to to previous check, the length of the other range is
equal to 0. They are equal. */
cmp_result = PyObject_Not(r0->length);
/* Return True or error to the caller.
>>> range(0) == range(2, 2, 2) # True
(True) gets caught here. Lengths are both zero. */
if (cmp_result != 0)
return cmp_result;
/* Compare the start values for the ranges, if they don't match
then we're not dealing with equal ranges. */
cmp_result = PyObject_RichCompareBool(r0->start, r1->start, Py_EQ);
/* Return False or error to the caller.
lens are equal, this checks their starting values
>>> range(0, 10) == range(10, 20) # False
Lengths are equal and non-zero, steps don't match.*/
if (cmp_result != 1)
return cmp_result;
/* Check if the length is equal to 1.
If start is the same and length is 1, they represent the same sequence:
>>> range(0, 10, 10) == range(0, 20, 20) # True */
one = PyLong_FromLong(1);
if (!one)
return -1;
cmp_result = PyObject_RichCompareBool(r0->length, one, Py_EQ);
Py_DECREF(one);
/* Return True or error to the caller. */
if (cmp_result != 0)
return cmp_result;
/* Finally, just compare their steps */
return PyObject_RichCompareBool(r0->step, r1->step, Py_EQ);
我也在这里散布了一些我自己的cmets;查看 @ajcr's answer 以获得 Python 等效项。