2012-07-13 12 views
127

संभव डुप्लिकेट:
Python “is” operator behaves unexpectedly with integersक्यों (0-6) है -6 = झूठा?

आज मैं अपनी परियोजना डिबग करने की कोशिश की और विश्लेषण करने के कुछ ही घंटों के बाद मैं यह मिल गया था:

>>> (0-6) is -6 
False 

लेकिन,

>>> (0-5) is -5 
True 

क्या आप मुझे समझा सकते हैं, क्यों? शायद यह किसी प्रकार का बग या बहुत अजीब व्यवहार है।

> Python 2.7.3 (default, Apr 24 2012, 00:00:54) [GCC 4.7.0 20120414 (prerelease)] on linux2 
>>> type(0-6) 
<type 'int'> 
>>> type(-6) 
<type 'int'> 
>>> type((0-6) is -6) 
<type 'bool'> 
>>> 
+6

अच्छी तरह से नीचे की ओर wacky – Wug

+25

आपको पहले स्थान पर 'is' का उपयोग करने का क्या कारण था? ऐसा कुछ ऐसा नहीं है जिसे अक्सर पायथन में इस्तेमाल किया जाना चाहिए, 'है/नहीं है' केस के अलावा। –

+3

@ रसेल की टिप्पणी सिर पर नाखून को हिट करती है - समस्या यह है कि कोई व्यक्ति स्पष्ट रूप से संख्याओं की तुलना करने के लिए "है" का उपयोग कर रहा था और उम्मीद की थी कि यह '=', गलत उम्मीद की तरह कार्य करे। – LarsH

उत्तर

150

-5 से 256 समावेशी करने के लिए सभी पूर्णांकों CPython के साथ एक ही पता साझा वैश्विक वस्तुओं के रूप में कैश नहीं किया जाता है, इस प्रकार is परीक्षण गुजरता है।

इस आर्टिफैक्ट को http://www.laurentluce.com/posts/python-integer-objects-implementation/ में विस्तार से समझाया गया है, और हम वर्तमान स्रोत कोड http://hg.python.org/cpython/file/tip/Objects/longobject.c में देख सकते हैं।

छोटे पूर्णांक को संदर्भित करने के लिए एक विशिष्ट संरचना का उपयोग किया जाता है और उन्हें साझा करने के लिए तेज़ी से पहुंच होती है। यह पूर्णांक वस्तुओं के लिए 262 पॉइंटर्स की एक सरणी है। उन पूर्णांक ऑब्जेक्ट्स को ऊपर वर्णित पूर्णांक ऑब्जेक्ट्स के ब्लॉक में प्रारंभिकरण के दौरान आवंटित किया जाता है। छोटी पूर्णांक सीमा -5 से 257 तक है। कई पायथन कार्यक्रम उस सीमा में पूर्णांक का उपयोग करके बहुत समय व्यतीत करते हैं, इसलिए यह एक स्मार्ट निर्णय है।

यह केवल सीपीथॉन का कार्यान्वयन विवरण है और आपको इस पर भरोसा नहीं करना चाहिए। उदाहरण के लिए, PyPy पूर्णांक के id कार्यान्वित ही वापस जाने के लिए है, तो (0-6) is -6 हमेशा सच है, भले ही वे "विभिन्न वस्तुओं" आंतरिक रूप से कर रहे हैं; यह आपको यह कॉन्फ़िगर करने की अनुमति देता है कि इस पूर्णांक कैशिंग को सक्षम करना है, और यहां तक ​​कि निचले और ऊपरी सीमाएं भी सेट करें। लेकिन सामान्य रूप से, विभिन्न उत्पत्ति से पुनर्प्राप्त वस्तुओं समान नहीं होंगे। यदि आप समानता की तुलना करना चाहते हैं, तो बस == का उपयोग करें।

+2

यही वह कहने जा रहा था, लेकिन मैं इसे ठीक से नहीं कह सकता था। +1 – mpen

+1

सकारात्मक पक्ष के लिए दिलचस्प skew। लेख में कहा गया है कि 'कई पायथन कार्यक्रम उस सीमा में पूर्णांक का उपयोग करके बहुत समय व्यतीत करते हैं, इसलिए देवों ने शायद इसे किसी भी तरह मापा है। मुझे लगता है कि ऋणात्मक संख्या अक्षर केवल इन दिनों त्रुटि कोड के लिए उपयोग किया जाता है ... –

+0

धन्यवाद @ केनीटीएम। –

26

यह एक बग नहीं है। is एक समानता परीक्षण नहीं है। == अपेक्षित परिणाम देगा।

इस व्यवहार के लिए तकनीकी कारण एक अजगर कार्यान्वयन या तो एक ही वस्तु है, या के रूप में विभिन्न वस्तुओं के रूप में ही निरंतर मूल्य के विभिन्न उदाहरणों का इलाज करने के लिए स्वतंत्र है। आपके द्वारा उपयोग किए जाने वाले पायथन कार्यान्वयन कुछ छोटे स्थिरांक को स्मृति-बचत कारणों के लिए एक ही ऑब्जेक्ट साझा करने के लिए चुनते हैं। आप इस व्यवहार पर संस्करण या विभिन्न पायथन कार्यान्वयन के समान संस्करण होने पर भरोसा नहीं कर सकते हैं।

+2

> 'is' समानता परीक्षण नहीं है। इस। 'is' एक पहचान परीक्षण है, यह देखने के लिए कि क्या दो वस्तुएं समान हैं। ऐसा ही होता है कि सीपीथॉन कार्यान्वयन में, कुछ int वस्तुओं को कैश किया जाता है। – Darthfett

+1

+1 कोई भी पायथन डेवलपर के लिए, यह मेरे लिए सबसे अच्छा समझाता है। –

29

पायथन स्टोरेज -5 - 256 में दुभाषिया में पूर्णांक स्टोर करता है: इसमें पूर्णांक ऑब्जेक्ट्स का पूल होता है जिससे इन पूर्णांक लौटाए जाते हैं। (0-5) और -5 नहीं बल्कि (0-6) और -6 इन के रूप में मौके पर ही बनाई गई हैं: यही कारण है कि उन वस्तुओं एक ही हैं।

यहाँ CPython के स्रोत कोड में स्रोत है:

#define NSMALLPOSINTS   257 
#define NSMALLNEGINTS   5 
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; 

(view CPython source code: /trunk/Objects/intobject.c)।स्रोत कोड निम्नलिखित टिप्पणी में शामिल हैं:

/* References to small integers are saved in this array so that they 
    can be shared. 
    The integers that are saved are those in the range 
    -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). 
*/ 

is ऑपरेटर फिर उन्हें (-5) की तुलना करेंगे के रूप में बराबर है, क्योंकि वे एक ही वस्तु (समान स्मृति स्थान), लेकिन दो अन्य नए पूर्णांकों (-6) पर किया जाएगा रहे हैं विभिन्न स्मृति स्थान (और फिर isTrue वापस नहीं आएगा)। ध्यान दें कि उपरोक्त स्रोत कोड में 257 सकारात्मक पूर्णांक के लिए है, इसलिए 0 - 256 (समावेशी) है।

(source)

16

क्योंकि CPython कुछ छोटे पूर्णांक और छोटे तार कैश और उस वस्तु एक ही id() के प्रत्येक उदाहरण देता है यह हो रहा है।

(0-5) और -5id() के लिए एक ही मूल्य है, जिसके लिए 0-6 और -6

>>> id((0-6)) 
12064324 
>>> id((-6)) 
12064276 
>>> id((0-5)) 
10022392 
>>> id((-5)) 
10022392 
इसी तार के लिए

सच नहीं है है:

>>> x = 'abc' 
>>> y = 'abc' 
>>> x is y 
True 
>>> x = 'a little big string' 
>>> y = 'a little big string' 
>>> x is y 
False 

स्ट्रिंग कैशिंग के बारे में अधिक जानकारी के लिए, पढ़ें: is operator behaves differently when comparing strings with spaces

+2

तो '-6' क्यों" बड़ा "और' -5' माना जाता है? कुछ "बड़े" को संभालने के लिए योग्यता मानदंड क्या है? – inspectorG4dget

+1

सीपीथॉन के लिए, -5 से 256 "interned" (कैश्ड) हैं। यह कुछ हद तक मनमाने ढंग से कार्यान्वयन विकल्प है। यदि किसी दिए गए इंटर्न वाले ऑब्जेक्ट का बहुत उपयोग किया जाता है, तो वहां संभावित रूप से बड़ी मेमोरी बचत होती है, लेकिन इसे प्रशिक्षित करने की लागत होती है (या तो रनटाइम या मेमोरी में) ताकि आप इसे सब कुछ के लिए नहीं करना चाहें। आईडी दिखाने के लिए –

+0

+1; मैं बस अपने जवाब में जोड़ने वाला था। –