docs - Python 3에서 range(0)== range(2, 2, 2)가 True 인 이유는 무엇입니까?




python 3 docs (4)

파이썬 3에서 다른 값으로 초기화 된 범위가 서로 동일한 이유는 무엇입니까?

통역사에서 다음 명령을 실행할 때 :

>>> r1 = range(0)
>>> r2 = range(2, 2, 2)
>>> r1 == r2
True

결과는 True 입니다. 왜 이럴까요? 매개 변수 값이 다른 두 개의 다른 range 객체가 동일한 것으로 취급되는 이유는 무엇입니까?


range 객체는 특별합니다.

파이썬은 range 객체를 Sequences 로 비교 range . 본질적으로 의미하는 것은 비교가 주어진 순서를 나타내는 방법 이 아니라 그들이 나타내는 것을 평가한다는 입니다.

start , stopstep 매개 변수가 완전히 다르다는 사실은 확장시 빈 목록을 나타 내기 때문에 여기서 아무런 차이가 없습니다.

예를 들어 첫 번째 range 개체는 다음과 같습니다.

list(range(0))  # []

두 번째 range 객체 :

list(range(2, 2, 2)) # []

둘 다 빈 목록을 나타내며 두 개의 빈 목록이 동일하기 때문에 ( True )이를 나타내는 range 개체도 마찬가지입니다.

결과적으로 완전히 다른 보이는 range 객체를 가질 수 있습니다. 이들이 동일한 순서를 나타내는 경우 동일하게 비교 됩니다.

range(1, 5, 100) == range(1, 30, 100) 

둘 다 단일 요소 [1] 갖는 목록을 나타내므로이 두 요소도 동일하게 비교됩니다.

아니요, range 객체는 실제로 특별합니다.

그러나 비교가 시퀀스를 나타내는 방법 을 평가하지는 않지만 range 값의 range 와 함께 start 값만 사용하여 비교 결과를 얻을 수 있습니다 . 이것은 비교 속도와 관련하여 매우 흥미로운 의미를 갖습니다.

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의 range 객체에만 적용됩니다. Python 2 range() 는 목록을 반환하는 일반 ol '함수이며 2.x xrange 객체에는 비교 기능이 없습니다 ( 이들뿐만 아니라 .. ) range 객체는 Python 3에 있습니다.

Python 3 range 객체의 소스 코드에서 직접 따옴표에 대한 @ajcr의 답변 을보십시오. 두 가지 범위의 비교가 실제로 무엇을 수반하는지 문서화되어 있습니다 : 간단한 빠른 조작. range_equals 함수는 EQNE 경우 range_richcompare 함수 에서 사용되며 PyRange_Type 유형의 경우 tp_richcompare 슬롯에 할당됩니다.

range_equals 의 구현은 여기에 추가하기가 꽤 읽기 range_equals (간단하기 때문에 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);

나는 또한 내 의견 중 일부를 여기에 뿌렸다. Python에 해당하는 @ajcr의 답변 을보십시오.


이 페이지의 우수 답변에 몇 가지 추가 정보를 추가하기 위해 두 range 객체 r0r1 대략 다음과 같이 비교 합니다 .

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

range 객체의 길이는 start , stopstep 매개 변수를 사용하여 쉽게 계산할 수 있습니다. 예를 들어 start == stop 인 경우 Python은 길이가 0임을 즉시 알 수 있습니다. 사소한 경우에는 Python이 start , stopstep 값을 사용하여 간단한 산술 계산 을 수행 할 수 있습니다.

따라서 range(0) == range(2, 2, 2) 경우 Python은 다음을 수행합니다.

  1. range(0)range(2, 2, 2) 가 메모리에서 다른 객체임을 알 수 range(0) .
  2. 두 객체의 길이를 계산합니다. 두 길이는 모두 0이므로 (두 객체에서 start == stop 이기 때문에) 다른 테스트가 필요합니다.
  3. len(range(0)) 이 0임을 알 수 있습니다. 이는 len(range(2, 2, 2)) 도 0 (이전 부등식 검정 실패)이므로 비교는 True 를 반환해야합니다.

range(0)range(0,0) 반환 range(0,0) . 1 단계에서 0부터 0까지 시작합니다. 세 번째 인수는 0 (기본적으로) 일 수 없으므로 정의되지 않습니다. 카운터의 동작이 없으므로 0에 도달하면 0에 도달 할 수 없습니다.

range(2, 2, 2)range(2, 2, 2) 반환 range(2, 2, 2) . 2에서 2까지 시작하지만 2 단계로 시작합니다. 다시 계산하지 않기 때문에 기본적으로 0입니다.

range(0) == range(2,2,2) 

사실 동일 합니다.


res = range(0) == range(2, 2, 2)

어디에:

range(0)

0 에서 0-0까지의 범위 (여기서는 step 가 기본값 1 동일 함)를 의미하며 값이없는 목록입니다.

range(2, 2, 2)

는 단계가 2 이고 값이없는 목록 인 2 에서 2 까지의 범위를 의미합니다.

따라서이 범위는 실제로 같습니다





python-internals