2011-06-22 33 views
15

क्या कोई मुझे निम्नलिखित व्यवहार समझा सकता है?शब्दकोशों में कुंजी के रूप में NaNs

>>> import numpy as np 
>>> {np.nan: 5}[np.nan] 
5 
>>> {float64(np.nan): 5}[float64(np.nan)] 
KeyError: nan 

यह पहले मामले में क्यों काम करता है, लेकिन दूसरे में नहीं? साथ ही, मैंने पाया कि निम्नलिखित करता है काम:

>>> a ={a: 5}[a] 
float64(np.nan) 
+0

यह हमेशा सत्य होगा: 'फ्लोट (' नैन ')! = फ्लोट (' नान ') ' – JBernardo

उत्तर

27

समस्या है कि यहाँ NaN के रूप में चल बिन्दु संख्या के लिए आईईईई मानक में परिभाषित, जो अपने आप के बराबर नहीं है है:

>>> float("nan") == float("nan") 
False 

जब एक शब्दकोश एक कुंजी दिखता है, यह लगभग यह करता है:

  1. देखा जाने वाला कुंजी हैश की गणना करें।

  2. उसी हैश के साथ dict में प्रत्येक कुंजी के लिए, जांचें कि यह देखने के लिए कुंजी से मेल खाता है या नहीं। इस चेक में

    ए शामिल हैं। ऑब्जेक्ट पहचान के लिए जांच कर रहा है: यदि शब्दकोश में कुंजी और कुंजी को देखने की कुंजी is ऑपरेटर द्वारा इंगित की गई एक ही वस्तु है, तो कुंजी मिली।

    बी। यदि पहली जांच विफल हुई, तो __eq__ ऑपरेटर का उपयोग करके समानता की जांच करें।

पहला उदाहरण सफल होता है np.nan के बाद से और np.nan एक ही वस्तु है, इसलिए यह कोई बात नहीं वे बराबर की तुलना नहीं है:

>>> numpy.nan is numpy.nan 
True 

दूसरे मामले में, np.float64(np.nan) और np.float64(np.nan) नहीं हैं एक ही वस्तु - दो निर्माता कॉल दो अलग-अलग वस्तुओं को बनाने:

>>> numpy.float64(numpy.nan) is numpy.float64(numpy.nan) 
False 

के बाद से वस्तुओं भी करना बराबर की तुलना नहीं करते, शब्दकोश निष्कर्ष निकाला जाता है कि कुंजी नहीं मिली है और KeyError फेंकता है।

तुम भी ऐसा कर सकते हैं:

>>> a = float("nan") 
>>> b = float("nan") 
>>> {a: 1, b: 2} 
{nan: 1, nan: 2} 

अंत में, यह एक saner विचार NaN एक शब्दकोश कुंजी के रूप में से बचने के लिए लगता है।

+1

ओप्स ... इसे सही नहीं देखा :) – JBernardo

+3

अंतिम कथन अधिक जोर देने योग्य है। – job

+0

क्या कोई गारंटी है कि सभी 'फ्लोट (' नैन ') के पास एक ही स्मृति स्थान है, यानी,' फ्लोट ('नैन') 'एक सिंगलटन है? इसके बिना, सादा 'फ्लोट (' नान ') का उपयोग भी एक बुरा विचार है। 'Np.nan' के बारे में वही सवाल। – max

1

कृपया ध्यान दें कि इस मामले अजगर 3.6 में अब और नहीं है:

>>> d = float("nan") 
>>> d 
nan 
>>> c = {"a": 3, d: 4} 
>>> c["a"] 
3 
>>> c[d] 
4 

मैं यह समझ के रूप में:

d = वस्तु नेन सी एक शब्दकोश 3 जिसमें जुड़े है करने के लिए "एक" और 4 नैन से जुड़ा हुआ है, लेकिन जिस तरह से पाइथन 3.6 आंतरिक शब्दकोशों में दिखता है, अब यह दो पॉइंटर्स की तुलना करता है, और यदि वे एक ही वस्तु को इंगित करते हैं तो वे मानते हैं कि समानता संरक्षित है।

इसका मतलब है कि हालांकि:

>>> d == d 
False 
क्योंकि कैसे IEEE754 निर्दिष्ट करता है कि नेन खुद के बराबर नहीं है की

, जब एक शब्दकोश को देख पहले संकेत ध्यान में रखा जाता है, और क्योंकि वे एक ही को इंगित नेन आपत्ति यह रिटर्न 4.

भी ध्यान रखें कि:

>>> e = float("nan") 
>>> e == d 
False 
>>> c[e] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
KeyError: nan 
>>> c[d] 
4 

तो नहीं हर नेन 4 की ओर इशारा करता है, तो IEEE754 किसी तरह से संरक्षित है। यह लागू किया गया था क्योंकि मान का सम्मान करते हुए कि नैन अपने आप के बराबर नहीं है, मानक को अनदेखा करने से अधिक दक्षता के तरीके को कम करता है। निश्चित रूप से क्योंकि आप किसी शब्दकोश में कुछ संग्रहीत कर रहे हैं जिसे आप पिछले संस्करणों में और अधिक नहीं पहुंच सकते हैं।

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