python - क्यों रेंज(0)== रेंज(2, 2, 2) पायथन 3 में सही है?




python-3.x range (4)

range ऑब्जेक्ट विशेष हैं:

पायथन Sequences रूप में 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 के मूल्यों का उपयोग करके प्राप्त किया जा सकता है , range वस्तुओं के len के साथ step ; तुलनाओं की गति के साथ इसके बहुत रोचक निहितार्थ हैं:

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 ने उल्लेख किया है, यह केवल पायथन 3 में रेंज ऑब्जेक्ट्स पर लागू होता है। पायथन 2 range() एक सादे ओएल 'फंक्शन है जो एक सूची देता है जबकि 2.x xrange ऑब्जेक्ट में तुलना xrange नहीं है ( और न केवल ये .. ) वह वस्तुएँ जो पायथन 3 में हैं।

पायथन 3 range ऑब्जेक्ट्स पर स्रोत कोड से सीधे उद्धरण के लिए @ ajcr के उत्तर को देखें। यह वहाँ प्रलेखित है कि दो अलग-अलग श्रेणियों के बीच तुलना वास्तव में क्या होती है: सरल त्वरित संचालन। range_equals फ़ंक्शन का उपयोग EQ और NE मामलों के लिए range_equals फ़ंक्शन में किया जाता है और PyRange_Type प्रकारों के लिए 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 के उत्तर को देखें।

पर्वतमाला जो विभिन्न मूल्यों के साथ आरंभीकृत होती है, पायथन 3 में एक दूसरे के बराबर होती है?

जब मैं अपने दुभाषिया में निम्नलिखित आदेशों पर अमल करता हूं:

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

परिणाम True । ऐसा क्यों है? अलग-अलग पैरामीटर मान वाले दो अलग-अलग range ऑब्जेक्ट को समान क्यों माना जाता है?


इस पृष्ठ पर उत्कृष्ट उत्तरों में कुछ अतिरिक्त विवरण जोड़ने के लिए, दो range वस्तुओं r0 और r1 की तुलना लगभग इस प्रकार की जाती है :

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 , stop और step पैरामीटर्स का उपयोग करके गणना करने के start । उदाहरण के लिए, जहां start == stop , उदाहरण के लिए, पायथन तुरंत जान सकता है कि लंबाई 0. है। गैर-तुच्छ मामलों में, पायथन केवल start , stop और step मान का उपयोग करके एक साधारण अंकगणितीय गणना कर सकता है।

तो range(0) == range(2, 2, 2) के मामले में range(0) == range(2, 2, 2) , पायथन निम्नलिखित करता है:

  1. यह देखता है कि range(0) और range(2, 2, 2) स्मृति में अलग-अलग वस्तुएं हैं।
  2. दोनों वस्तुओं की लंबाई की गणना करता है; दोनों की लंबाई 0 है (क्योंकि start == stop दोनों वस्तुओं में रुकें) इसलिए एक और परीक्षण की आवश्यकता है।
  3. देखता है कि len(range(0)) 0. है। इसका मतलब है कि len(range(2, 2, 2)) भी 0 है (असमानता के लिए पिछला परीक्षण विफल) और इसलिए तुलना True होनी चाहिए।

range(0) रिटर्न range(0,0) । आप चरण 1 के साथ 0 से 0 तक शुरू करते हैं, जो अपरिभाषित है क्योंकि तीसरा तर्क 0 [डिफ़ॉल्ट रूप से] नहीं हो सकता है। आप 0 के साथ नहीं पहुंच सकते। 1. इसलिए काउंटर की कार्रवाई नहीं हुई, इसलिए 0।

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