9

के साथ व्यवहार करता है जब यूनिट परीक्षण करने पर यूनिट एक उलझन में समस्या आई। मॉड्यूल वास्तव में मूल्यों कास्टिंग कर रहा है और मैं इन मानों की तुलना करना चाहता हूं।'है' ऑपरेटर अप्रत्याशित रूप से फ्लोट्स

>>> float(0) is 0.0 
False 
>>> float(0) is float(0) 
False 
:

वहाँ == और is (आंशिक रूप से, मैं अंतर से सावधान कर रहा हूँ)

>>> 0.0 is 0.0 
True # as expected 
>>> float(0.0) is 0.0 
True # as expected 

के साथ तुलना में एक फर्क है अब तक उम्मीद थी, लेकिन यहाँ मेरी "समस्या" है

क्यों? कम से कम आखिरी वास्तव में मुझे भ्रमित कर रहा है। float(0) और float(0.0) का आंतरिक प्रतिनिधित्व बराबर होना चाहिए। == के साथ तुलना के रूप में काम कर रहा है।

+2

संबंधित: http://stackoverflow.com/questions/132988/is-there-a-difference-between-and-is-in-python – Elazar

+1

आपका प्रश्न उत्तर देने योग्य है, लेकिन यदि आप इस समस्या को पार करते हैं असली कोड, कोड शायद गलत है और तय किया जाना चाहिए। इस तरह से फ्लोट्स के बीच संदर्भ पहचान का परीक्षण करने के लिए लगभग (लगभग) कोई कारण नहीं है। – Elazar

+1

अजीब बात यह है कि यद्यपि मैं इसे पुनः उत्पन्न कर सकता हूं, सभी आईडी (0.0) ',' आईडी (फ्लोट (0.0)) 'और' आईडी (फ्लोट (0)) 'वही मान वापस कर सकते हैं। ... यही है, मान वैसा ही है यदि मैं इंटरैक्टिव शैल में दूसरे के बाद निष्पादित करता हूं, लेकिन अगर मैं 'आईडी (फ्लोट (0.0)), आईडी (फ्लोट (0))' (एक टुपल के रूप में) तो आईडी अलग है। कोई स्पष्टीकरण? –

उत्तर

20

यह is काम करता है के साथ क्या करना है। यह मूल्य के बजाय संदर्भों की जांच करता है। यह True देता है यदि तर्क एक ही वस्तु को सौंपा गया है।

इस मामले में, वे अलग-अलग उदाहरण हैं; float(0) और float(0) समान मूल्य == है, लेकिन जहां तक ​​पाइथन का संबंध है, वे अलग-अलग इकाइयां हैं। सीपीथन कार्यान्वयन भी इस श्रेणी में सिंगलटन वस्तुओं के रूप में पूर्णांक को कैश करता है ->[x | एक्स ∈ ℤ ∧ -5 ≤ एक्स ≤ 256]:

>>> 0.0 is 0.0 
True 
>>> float(0) is float(0) # Not the same reference, unique instances. 
False 

इस उदाहरण में हम पूर्णांक कैशिंग सिद्धांत प्रदर्शित कर सकते हैं:

>>> a = 256 
>>> b = 256 
>>> a is b 
True 
>>> a = 257 
>>> b = 257 
>>> a is b 
False 

अब, तैरता float() के लिए पारित कर रहे हैं, फ्लोट शाब्दिक बस वापस लौटाया जाता है (शॉर्ट सर्किट), जैसा कि एक ही संदर्भ में उपयोग किया जाता है, क्योंकि मौजूदा फ्लोट से एक नई फ्लोट को तुरंत चालू करने की आवश्यकता नहीं है:

>>> 0.0 is 0.0 
True 
>>> float(0.0) is float(0.0) 
True 

यह int() भी उपयोग करके आगे का प्रदर्शन किया जा सकता है:

>>> int(256.0) is int(256.0) # Same reference, cached. 
True 
>>> int(257.0) is int(257.0) # Different references are returned, not cached. 
False 
>>> 257 is 257 # Same reference. 
True 
>>> 257.0 is 257.0 # Same reference. As @Martijn Pieters pointed out. 
True 

हालांकि, is के परिणाम भी गुंजाइश उस में क्रियान्वित किया जा रहा है पर निर्भर हैं (इस सवाल की अवधि से परे /स्पष्टीकरण) , कृपया उपयोगकर्ता को देखें: @Jimcode objects पर शानदार स्पष्टीकरण। यहां तक ​​कि अजगर के दस्तावेज़ इस व्यवहार पर एक खंड शामिल:

[7] स्वत: कचरा-संग्रह, नि: शुल्क सूचियों, और वर्णनकर्ता के गतिशील स्वभाव, आप कर सकते हैं के कारण is ऑपरेटर के कुछ उपयोगों में प्रतीत होता है असामान्य व्यवहार, जैसे कि उदाहरण विधियों या स्थिरांक के बीच तुलना शामिल है। अधिक जानकारी के लिए अपने दस्तावेज की जांच करें।

+0

'फ्लोट (17.0) फ्लोट (17.0)' रिटर्न 'ट्रू 'है लेकिन' फ्लोट (17.0) फ्लोट है ('17 .0') 'रिटर्न' गलत '->' फ्लोट (some_value) 'सिर्फ मूल फ्लोट लौटा रहा है इसलिए नहीं नया उदाहरण बनाया गया है (अगर कुछ_वृत्त एक फ्लोट है ...)? –

+0

@Jim ने उत्तर दिया –

+0

सीपीथन फ्लोट कैश नहीं करता है। आप निरंतर फोल्डिंग का संयोजन देख रहे हैं और 'फ्लोट' कन्स्ट्रक्टर सीधे उन मामलों के लिए फ़्लोट्स पास कर रहा है जहां 'सत्य' है 'सत्य'। – user2357112

9

एक float वस्तु float() को आपूर्ति की जाती है, तो CPython * बस एक नई वस्तु बनाने के बिना वापस करती है।

यह PyNumber_Float में देखा जा सकता है (जो अंततः float_new से कहा जाता है) जहां किसी चीज़ o में PyFloat_CheckExact चिह्नित है और पारित; यदि True, यह सिर्फ अपने संदर्भ गिनती बढ़ जाती है और यह देता है:

if (PyFloat_CheckExact(o)) { 
    Py_INCREF(o); 
    return o; 
} 

नतीजतन, वस्तु की id ही रहता है। तो अभिव्यक्ति

>>> float(0.0) is float(0.0) 

को कम कर देता है:

>>> 0.0 is 0.0 

लेकिन क्यों कि बराबर True करता है? खैर, CPython में कुछ छोटे अनुकूलन हैं।

इस मामले में, यह आपके आदेश में 0.0 की दो घटनाओं के लिए एक ही ऑब्जेक्ट का उपयोग करता है क्योंकि वे the same code object (लघु अस्वीकरण: वे एक ही लॉजिकल लाइन पर हैं) का हिस्सा हैं; इसलिए is परीक्षण सफल होगा। पहचान के लिए

यह आगे यदि आप अलग-अलग पंक्तियों में float(0.0) (या, ; द्वारा सीमांकित) पर अमल पुष्टि की जा सकती है और फिर जांच:

a = float(0.0); b = float(0.0) # Python compiles these separately 
a is b # False 

दूसरी ओर, यदि एक int (या एक str) की आपूर्ति की जाती है, सीपीथॉन नयाfloat ऑब्जेक्ट बना देगा और उसे वापस कर देगा। इसके लिए, यह क्रमशः PyFloat_FromDouble और PyFloat_FromString का उपयोग करता है।

प्रभाव है कि लौटे वस्तुओं id रों (जो is साथ पहचान की जांच करने के लिए प्रयोग किया जाता) में मतभेद है:

# Python uses the same object representing 0 to the calls to float 
# but float returns new float objects when supplied with ints 
# Thereby, the result will be False 
float(0) is float(0) 

* नोट: सभी पिछले उल्लेख व्यवहार के कार्यान्वयन के लिए लागू होता है C यानी CPython में पायथन। अन्य कार्यान्वयन विभिन्न व्यवहार प्रदर्शित कर सकते हैं। संक्षेप में, इस पर निर्भर नहीं है

+0

आपके विवरण के साथ अपने उत्तर के लिए Thx पूरी तरह से मैं mrdomoboto के उत्तर को सही के रूप में स्वीकार करूंगा (मुझे इस कठिन निर्णय से नफरत है ...) –

+1

मैंने कोड ऑब्जेक्ट्स पर एक फुटनोट (महान स्पष्टीकरण बीटीडब्ल्यू!) के रूप में अपना हिस्सा जोड़ा। – ospahiu

संबंधित मुद्दे