2014-04-18 6 views
23

पायथन में, मुझे पता है कि किसी दिए गए ऑब्जेक्ट के लिए मान __hash__ मान उस ऑब्जेक्ट के जीवनकाल के लिए समान होना चाहिए। लेकिन, जिज्ञासा से, अगर ऐसा नहीं होता तो क्या होता है? इस कारण किस तरह का विनाश होगा?क्या होता है यदि किसी ऑब्जेक्ट का __hash__ बदलता है?

class BadIdea(object): 
    def __hash__(self): 
    return random.randint(0, 10000) 

मैं __contains__ और __getitem__ अजीब तरीके से व्यवहार होता है, और dicts और सेट उसकी वजह से अजीब अभिनय करेंगे। आप भी dict/set में "अनाथ" मानों के साथ समाप्त हो सकते हैं।

और क्या हो सकता है? क्या यह दुभाषिया, या भ्रष्ट आंतरिक संरचनाओं को दुर्घटनाग्रस्त कर सकता है?

+1

इस तरह के कोड को कभी भी "क्रैश" या "भ्रष्ट" रन-टाइम नहीं होना चाहिए, लेकिन वास्तव में dict/set उपयोग वास्तव में .. समस्याग्रस्त हो जाएगा। – user2864740

+2

शायद आपके 'BadIdea' ऑब्जेक्ट के बारे में सबसे बुरी चीजों में से एक यह तथ्य है कि यह केवल 10,000 संभावित हैंश का एक सेट तैयार करने में सक्षम है, इस प्रकार 'अपेक्षाकृत महंगा हैश टकराव '' '' '' '' '' '' '' ' के साथ सौदा करना है। –

+1

@ दो-बिट एल्केमिस्ट अच्छी तरह से आपकी समस्याओं का कम से कम है। – arshajii

उत्तर

16

आपकी मुख्य समस्या वास्तव में डिक्ट्स और सेट के साथ होगी। यदि आप किसी ऑब्जेक्ट को किसी dict/set में सम्मिलित करते हैं, और उस ऑब्जेक्ट के हैश में परिवर्तन होते हैं, तो जब आप उस ऑब्जेक्ट को पुनर्प्राप्त करने का प्रयास करते हैं तो आप अलग-अलग स्पॉट को निर्देश/सेट के अंतर्निहित सरणी में देख सकते हैं और इसलिए नहीं मिलेगा वस्तु। यही कारण है कि क्यों dict कुंजी हमेशा अपरिवर्तनीय होना चाहिए।

यहां एक छोटा उदाहरण है: मान लीजिए कि हम एक dict में o डाल दें, और o की प्रारंभिक हैश 3. है हम कुछ इस तरह करना होगा (एक मामूली सरलीकरण लेकिन भर में बिंदु हो जाता है):

 
Hash table: 

    0 1 2 3 4 5 6 7 
+---+---+---+---+---+---+---+---+ 
| | | | o | | | | | 
+---+---+---+---+---+---+---+---+ 
      ^
       we put o here, since it hashed to 3 

अब मान लें कि o का हैश 6 में बदल गया है। यदि हम dict से o पुनर्प्राप्त करना चाहते हैं, तो हम स्पॉट 6 देखेंगे, लेकिन वहां कुछ भी नहीं है! डेटा संरचना से पूछताछ करते समय यह झूठी नकारात्मक होगी। हकीकत में, उपरोक्त सरणी के प्रत्येक तत्व में एक नियम के मामले में इसके साथ "मूल्य" जुड़ा हो सकता है, और एक ही स्थान में कई तत्व हो सकते हैं (उदा। hash collision)। साथ ही, तत्व को कहां रखना है, यह तय करते समय हम आम तौर पर हैश मान मॉड्यूलो सरणी के आकार लेते हैं। इन सभी विवरणों के बावजूद, उपर्युक्त उदाहरण अभी भी सटीक रूप से बताता है कि किसी ऑब्जेक्ट के हैश कोड में परिवर्तन होने पर क्या गलत हो सकता है।

क्या यह दुभाषिया, या दूषित आंतरिक संरचनाओं को क्रैश कर सकता है?

नहीं, ऐसा नहीं होगा। जब हम कहते हैं कि किसी ऑब्जेक्ट के हैश बदलना "खतरनाक" है, तो हम इस अर्थ में खतरनाक हैं कि यह अनिवार्य रूप से हैशिंग के उद्देश्य को हरा देता है और अगर कोड के बारे में तर्क करना मुश्किल हो जाता है तो कोड मुश्किल हो जाता है। हम इस अर्थ में खतरनाक नहीं हैं कि यह दुर्घटनाओं का कारण बन सकता है।

8

इसके बारे में गिथब पर एक शानदार पोस्ट है: What happens when you mess with hashing। (दूसरे शब्दों में, एक hashable वस्तु अपरिवर्तनीय होना चाहिए)

  • एक वस्तु का हैश वस्तु के जीवनकाल में नहीं बदलता: सबसे पहले, आप को पता है कि अजगर (लेख से उद्धृत) की उम्मीद की जरूरत है।

  • a == b का तात्पर्य hash(a) == hash(b) (ध्यान दें कि रिवर्स हैश टक्कर के मामले में नहीं हो सकता है)।

यहाँ कोड उदाहरण जो एक प्रकार हैश की समस्या दिखाने के लिए, एक अलग वर्ग उदाहरण के साथ है, लेकिन विचार ही रहता है:

>>> class Bad(object): 
...  def __init__(self, arg): 
...   self.arg = arg 
...  def __hash__(self): 
...   return hash(self.arg) 
... 
>>> Bad(1) 
<__main__.Bad object at ...> 
>>> hash(Bad(1)) 
1 
>>> a = Bad(1) 
>>> b = {a:1} 
>>> a.arg = 2 
>>> hash(a) 
2 
>>> b[a] 
Traceback (most recent call last): 
... 
KeyError: <__main__.Bad object at ...> 

यहाँ, हम परोक्ष हैश बदल उस के तर्क को म्यूट करके एक हैश की गणना करने के लिए प्रयोग किया जाता है। नतीजतन, वस्तु अब एक शब्दकोश में नहीं मिली है, जो वस्तु को खोजने के लिए हैश का उपयोग करती है।

ध्यान दें कि पायथन मुझे ऐसा करने से नहीं रोकता है। अगर मैं चाहता हूं तो मैं इसे बना सकता हूं, __setattr__AttributeError बढ़ाकर, लेकिन फिर भी मैं ऑब्जेक्ट के __dict__ को संशोधित करके इसे जबरन बदल सकता हूं। इसका मतलब यह है कि जब हम कहते हैं कि पायथन एक "सहमति वयस्क" भाषा है।

यह अजगर दुर्घटना नहीं होगा लेकिन अप्रत्याशित व्यवहार dict/सेट और वस्तु हैश के आधार पर सब कुछ के साथ क्या होगा।

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