Why is range(0) == range(2, 2, 2) True in Python 3?
为什么用不同值初始化的范围在python 3中互相比较相等?
当我在解释器中执行以下命令时:
1 2 3 4 | >>> r1 = range(0) >>> r2 = range(2, 2, 2) >>> r1 == r2 True |
结果是
python将把
例如,第一个
1 | list(range(0)) # [] |
第二个
1 | list(range(2, 2, 2)) # [] |
两者都代表一个空列表,由于两个空列表比较相等(
因此,您可以拥有完全不同的外观的
1 | range(1, 5, 100) == range(1, 30, 100) |
两者都用一个元素
但是,请注意,即使比较没有评估它们如何表示序列,也可以仅使用
1 2 3 4 5 | r0 = range(1, 1000000) r1 = range(1, 1000000) l0 = list(r0) l1 = list(r1) |
范围比较超快:
1 2 3 | %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 |
另一方面,清单……
1 2 | %timeit l0 == l1 10 loops, best of 3: 27.8 ms per loop |
是啊。。
正如@superbiasedman所指出的,这只适用于python 3中的range对象。python 2
查看@ajcr的答案,直接从python 3
我相信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | /* 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对python等价物的回答。
直接引用文档(强调我的):
Testing range objects for equality with == and != compares them as
sequences. That is, two range objects are considered equal if they
represent the same sequence of values. (Note that two range objects
that compare equal might have different start, stop and step
attributes, for example range(0) == range(2, 1, 3) or range(0, 3, 2)
== range(0, 4, 2).)
如果将EDOCX1[0]与"相同"列表进行比较,您将得到不平等,如文档中所述:
Objects of different types, except different numeric types, never
compare equal.
例子:
1 2 3 4 5 6 7 8 | >>> type(range(1)) <class 'range'> >>> type([0]) <class 'list'> >>> [0] == range(1) False >>> [0] == list(range(1)) True |
注意,这只显式地适用于Python3。在python 2中,
为了在本页的优秀答案中增加一些额外的细节,对两个
1 2 3 4 5 6 7 8 9 10 11 | if r0 is r1: # True if r0 and r1 are same object in memory return True if len(r0) != len(r1): # False if different number of elements in sequences return False if not len(r0): # True if r0 has no elements return True if r0.start != r1.start: # False if r0 and r1 have different start values return False if len(r0) == 1: # True if r0 has just one element return True return r0.step == r1.step # if we made it this far, compare step of r0 and r1 |
使用
因此,在
哪里:
1 | range(0) |
指从
1 | range(2, 2, 2) |
指步骤等于
所以,这些范围是相等的
1 | range(0) == range(2,2,2) |
是的,完全一样。