2016-07-18 8 views
6

मैं सेट में उसी हैश ऑब्जेक्ट को जोड़ने से रोकने के लिए set() और __hash__ विधि python क्लास का उपयोग कर रहा हूं। python data-model document के अनुसार, set() एक ही वस्तु के समान हीश ऑब्जेक्ट पर विचार करें और बस उन्हें एक बार जोड़ें।पायथन - कक्षा __hash__ विधि और सेट

लेकिन यह नीचे के रूप में अलग अलग बर्ताव करता है:

class MyClass(object): 

    def __hash__(self): 
     return 0 

result = set() 
result.add(MyClass()) 
result.add(MyClass()) 

print(len(result)) # len = 2 

जबकि स्ट्रिंग मान के मामले में, यह सही ढंग से काम करता है।

result.add('aida') 
result.add('aida') 

print(len(result)) # len = 1 

मेरा प्रश्न है: क्यों एक ही हैश ऑब्जेक्ट सेट में समान नहीं हैं? __hash__ और __eq__:

उत्तर

10

आपकी पठन सही नहीं है। समानता जांच के लिए __eq__ विधि का उपयोग किया जाता है। दस्तावेज सिर्फ यह बताते हैं कि __hash__ मान 2 ऑब्जेक्ट्स a और b के लिए भी होना चाहिए जिसके लिए a == b (यानी a.__eq__(b)) सत्य है।

यह एक आम तर्क गलती है: a == b सच किया जा रहा तात्पर्य कि hash(a) == hash(b) भी सच है। हालांकि निहितार्थ का अर्थ समतुल्य का अर्थ नहीं है, hash(a) == hash(b) का अर्थ यह होगा कि a == b

MyClass के सभी उदाहरणों को एक दूसरे के बराबर तुलना करने के लिए, आपको उनके लिए __eq__ विधि प्रदान करने की आवश्यकता है; अन्यथा पाइथन की तुलना की तुलना में उनकी तुलना करेगा।यह कर सकते हैं:

class MyClass(object): 
    def __hash__(self): 
     return 0 
    def __eq__(self, other): 
     # another object is equal to self, iff 
     # it is an instance of MyClass 
     return isinstance(other, MyClass) 

अब:

>>> result = set() 
>>> result.add(MyClass()) 
>>> result.add(MyClass()) 
1 

हकीकत में आप अपनी वस्तु के उन गुणों है कि __eq__ तुलना के लिए उपयोग किया जाता है पर __hash__ आधार चाहते हैं, उदाहरण के लिए:

class Person 
    def __init__(self, name, ssn): 
     self.name = name 
     self.ssn = ssn 

    def __eq__(self, other): 
     return isinstance(other, Person) and self.ssn == other.ssn 

    def __hash__(self): 
     # use the hashcode of self.ssn since that is used 
     # for equality checks as well 
     return hash(self.ssn) 

p = Person('Foo Bar', 123456789) 
q = Person('Fake Name', 123456789) 
print(len({p, q}) # 1 
5

सेट एक वस्तु hashable बनाने के लिए दो तरीकों की जरूरत है। दो उदाहरण समान हैश मान वापस कर सकते हैं जब उन्हें बराबर माना जाता है। एक उदाहरण को एक सेट में पहले से मौजूद माना जाता है यदि हैश दोनों सेट और में मौजूद है, उदाहरण को सेट में उसी हैश के उदाहरणों में से एक के बराबर माना जाता है।

आपका वर्ग __eq__ को लागू नहीं करता, इसलिए डिफ़ॉल्ट object.__eq__ बजाय जो केवल सच रिटर्न अगर obj1 is obj2 भी सच है प्रयोग किया जाता है,। दूसरे शब्दों में, दो उदाहरणों को केवल तभी माना जाता है जब वे सटीक उसी उदाहरण हैं।

सिर्फ इसलिए कि उनके हैंश मैच हैं, उन्हें सेट के रूप में अद्वितीय नहीं बनाते हैं; अलग-अलग हैंश के साथ भी ऑब्जेक्ट्स एक ही हैश टेबल स्लॉट में समाप्त हो सकते हैं, क्योंकि तालिका आकार के विरुद्ध हैश के मॉड्यूलस का उपयोग किया जाता है।

अपने एक कस्टम जोड़े __eq__ विधि है कि True जब दो उदाहरणों बराबर होना करने वाले हैं देता है:

def __eq__(self, other): 
    if not isinstance(other, type(self)): 
     return False 
    # all instances of this class are considered equal to one another 
    return True 
संबंधित मुद्दे