Ответ 1
Объекты range
являются специальными:
Python будет сравнивать range
объекты как Последовательности. Что по существу означает, что сравнение не оценивает как, они представляют заданную последовательность, а скорее , что они представляют.
Тот факт, что параметры 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
объекты действительно особенные:
Однако обратите внимание, что, хотя сравнение не оценивает, как они представляют последовательность, результат сравнения может быть достигнут с использованием исключительно значений start
, step
вместе с len
объектов range
; это имеет очень интересные последствия со скоростью сравнений:
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
не имеет сравнительных возможностей (и не только эти..), что объекты range
имеют в Python 3.
Посмотрите @ajcr answer для цитат непосредственно из исходного кода объектов Python 3 range
. В нем задокументировано то, что фактически подразумевает сравнение двух разных диапазонов: простые быстрые операции. Функция range_equals
используется в range_richcompare
function для EQ
и NE
и назначается слоту tp_richcompare
для PyRange_Type
типов.
Я полагаю, что реализация 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);
Я также разбросал некоторые мои собственные комментарии; посмотрите @ajcr answer для эквивалента Python.