क्या हो रहा है यह समझने के लिए, आपको यह समझना होगा कि in
ऑपरेटर, membership test, विभिन्न प्रकारों के लिए व्यवहार करता है।
सूचियों के लिए, मूलभूत रूप से सूचीबद्ध सूचियों के कारण यह बहुत आसान है: ऑर्डर किए गए सरणी जो डुप्लिकेट की परवाह नहीं करते हैं। यहां सदस्यता परीक्षा का पालन करने का एकमात्र संभावित तरीका सूची में पुन: प्रयास करना है और प्रत्येक आइटम को समानता पर जांचना है। इस तरह कुछ:
# x in lst
for item in lst:
if x == item:
return True
return False
शब्दकोश थोड़ा अलग हैं: वे हैश टेबल हैं कुंजी कुंजी अद्वितीय होने के लिए हैं। हैश टेबल को हैशबल होने की आवश्यकता होती है जिसका अनिवार्य रूप से मतलब है कि एक स्पष्ट फ़ंक्शन होना आवश्यक है जो ऑब्जेक्ट को पूर्णांक में परिवर्तित करता है। इस हैश मान को तब हैश तालिका में कहीं भी कुंजी/मान मैपिंग डालने के लिए उपयोग किया जाता है।
चूंकि हैश मान निर्धारित करता है कि हैश तालिका में एक आइटम कहाँ रखा गया है, यह महत्वपूर्ण है कि ऑब्जेक्ट्स जो समान हैंश मान के समान हैं। तो निम्नलिखित निहितार्थ सत्य होना चाहिए: x == y => hash(x) == hash(y)
। रिवर्स को सत्य होने की आवश्यकता नहीं है; यह पूरी तरह मान्य है कि अलग-अलग ऑब्जेक्ट्स समान हैश मान उत्पन्न करते हैं।
जब किसी शब्दकोश पर सदस्यता परीक्षण किया जाता है, तो शब्दकोश सबसे पहले हैश मान की तलाश करेगा। यदि यह इसे पा सकता है, तो यह सभी वस्तुओं पर समानता जांच करेगा; अगर यह हैश मान नहीं मिला है, तो यह मान लिया गया है कि यह एक अलग वस्तु है:
# x in dct
h = hash(x)
items = getItemsForHash(dct, h)
for item in items:
if x == item:
return True
# items is empty, or no match inside the loop
return False
जब से तुम वांछित परिणाम है जब एक सूची के खिलाफ एक सदस्यता परीक्षण, इसका मतलब है कि आपके वस्तु समानता तुलना लागू करता है का उपयोग कर पाने के (__eq__
) सही ढंग से। लेकिन जब से तुम सही परिणाम जब एक शब्दकोश का उपयोग कर नहीं मिलता है, वहाँ एक __hash__
कार्यान्वयन समानता तुलना कार्यान्वयन के साथ समन्वय से बाहर है कि लगता है:
>>> class SomeType:
def __init__ (self, x):
self.x = x
def __eq__ (self, other):
return self.x == other.x
def __hash__ (self):
# bad hash implementation
return hash(id(self))
>>> l = [SomeType(1)]
>>> d = { SomeType(1): 'x' }
>>> x = SomeType(1)
>>> x in l
True
>>> x in d
False
ध्यान दें कि अजगर 2 में नई शैली कक्षाओं के लिए (कक्षाएं जो object
से प्राप्त होती हैं), यह "खराब हैश कार्यान्वयन" (जो ऑब्जेक्ट आईडी पर आधारित है) डिफ़ॉल्ट है। इसलिए जब आप अपना खुद का __hash__
फ़ंक्शन लागू नहीं करते हैं, तो यह अभी भी उस का उपयोग करता है।इसका अंततः मतलब है कि जब तक कि आपके __eq__
केवल एक पहचान जांच (डिफ़ॉल्ट) निष्पादित करता है, हैश फ़ंक्शन सिंक से बाहर हो जाएगा।
तो समाधान __hash__
को इस तरह से कार्यान्वित करना है कि यह __eq__
में उपयोग किए गए नियमों के साथ संरेखित हो। उदाहरण के लिए, यदि आप दो सदस्यों की तुलना self.x
और self.y
की तुलना करते हैं, तो आपको उन दो सदस्यों पर एक कंपाउंड हैश का उपयोग करना चाहिए।
तो एक वर्ग परिभाषित करता है: अगर यह परिवर्तनशील है कि आप एक वस्तु hashable नहीं करना चाहिए
class SomeType (object):
def __init__ (self, x, y):
self.x = x
self.y = y
def __eq__ (self, other):
return self.x == other.x and self.y == other.y
def __hash__ (self):
return hash((self.x, self.y))
नोट: ऐसा करने के लिए सबसे आसान तरीका है उन मूल्यों की एक टपल के हैश मान वापस जाने के लिए है म्यूटेबल ऑब्जेक्ट्स और __eq__()
विधि लागू करता है, इसे __hash__()
लागू नहीं करना चाहिए, क्योंकि हैशबल संग्रह के कार्यान्वयन के लिए एक कुंजी हैश मान अपरिवर्तनीय है (यदि ऑब्जेक्ट का हैश मान बदलता है, तो यह गलत हैश बाल्टी में होगा)।
@vaultah यह करना पड़ता है (अन्यथा आप एक unhashable लेखन त्रुटि मिलेगा), लेकिन कार्यान्वयन '__eq__' के कार्यान्वयन के साथ गठबंधन नहीं होने की संभावना है। – poke
आपने 'to_user' और मुख्य वर्ग को कैसे कार्यान्वित किया? पाइथन शब्दकोश डुप्लिकेट ऑब्जेक्ट्स को संरक्षित नहीं करता है क्योंकि आपके पास समान '__hash__' मान है, लेकिन यदि आप प्रत्येक कक्षा में एक से अधिक उदाहरण बनाते हैं तो आपको विभिन्न हैश मान के साथ एक नई वस्तु मिल जाएगी। (इस बिंदु के कारण उनके पास समान प्रतिनिधित्व है), लेकिन परिणामस्वरूप आपका शब्दकोश प्रतिनिधित्व नहीं होगा क्योंकि वे एक ही तार हैं और इसलिए एक ही हैश मान है। – Kasramvd
@poke आपने +1 के नीचे एक अच्छा उत्तर पोस्ट किया है। हालांकि, unhashable TypeError के बारे में आपकी टिप्पणी सही नहीं है, [जैसा कि इस उत्तर में दिखाया गया है] (http://stackoverflow.com/a/17445665/1431750)। – aneroid