2012-10-19 18 views
5

मैं दृश्यों की तुलना के लिए set().issubset() उपयोग करने के लिए कोशिश कर रहा हूँ। जैसा कि आप कल्पना कर सकते हैं, यह अपेक्षित काम नहीं कर रहा है;) अग्रिम में: लंबे कोड-ब्लॉब के लिए खेद है।अजगर सेट()। Issubset() काम नहीं कर के रूप में की उम्मीद

$ python 
Python 2.7.2 (v2.7.2:8527427914a2, Jun 11 2011, 15:22:34) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import issubsettest 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "issubsettest.py", line 52, in <module> 
    assert yy.issubset(xx), "issubset not working :(" 
AssertionError: issubset not working :(
>>> 

मैं यहाँ क्या याद आ रही है: कोड ऊपर

class T(object): 
    def __init__(self, value, attributes = None): 
    self.value = value 
    self.attributes = Attributes(attributes) 

    def __eq__(self, other): 
    if not isinstance(other, T): 
     return False 
    if self.value == other.value and self.attributes == other.attributes: 
     return True 
    else: 
     return False 

    def __ne__(self, other): 
    if not isinstance(other, T): 
     return True 
    if self.value != other.value or self.attributes != other.attributes: 
     return True 
    else: 
     return False 

class Attributes(dict): 
    def __init__(self, attributes): 
    super(dict, self) 
    self.update(attributes or dict()) 

    def __eq__(self, other): 
    if self.items() == other.items(): 
     return True 
    else: 
     return False 

    def __ne__(self, other): 
    if not self.items() == other.items(): 
     return True 
    else: 
     return False 

    def __cmp__(self, other): 
    return self.items().__cmp__(other.items()) 


x = [T("I", {'pos': 0}), T("am", {'pos': 1}), T("a", {'pos': 2}), T("test", {'pos': 3})] 
y = [T("a", {'pos': 2}), T("test", {'pos': 3})] 
xx = set(x) 
yy = set(y) 

assert y[0] == x[2], "__eq__ did fail, really?" #works 
assert y[1] == x[3], "__eq__ did fail, really?" #works 
assert xx-(yy-xx) == xx, "set subtract not working" #works, but is nonsense. see accepted answer 
assert not xx.issubset(yy), "i am doing it wrong..." #works 
assert yy.issubset(xx), "issubset not working :(" #FAILS! 

चल रहा है पिछले दावे विफल रहता है?

+0

मुझे लगता है कि ऐसा इसलिए है क्योंकि उपयोगकर्ता –

+0

मुझे लगता है कि समस्या यह है कि आपकी कक्षा 'टी' विधि' __hash__' को ओवरराइड नहीं करती है। [दस्तावेज़ीकरण] देखें (http://docs.python.org/reference/datamodel.html#object.__hash__): * यदि यह __cmp __() या __eq __() को परिभाषित करता है लेकिन __hash __() नहीं है, तो इसके उदाहरण उपयोग योग्य नहीं होंगे हैश संग्रह में।* – halex

+2

मैंने अभी आपके कोड को पायथन 3.3 के साथ परीक्षण किया है, जो त्रुटि देता है: 'TypeError: unhashable type:' t'' पंक्ति 'xx = set (x)' पर यह निश्चित रूप से '__hash__' की कमी है। – halex

उत्तर

9

आपकी ऑब्जेक्ट्स को उनके id द्वारा धोया जा रहा है (आपने __hash__ को ओवरराइड नहीं किया है)। बेशक वे xx और yy के बाद से सबसेट नहीं हैं क्योंकि अद्वितीय ऑब्जेक्ट्स हैं।

ऐसा करने में, आप __hash__ समारोह के कुछ प्रकार के साथ आने की जरूरत है। __hash__ हमेशा एक वस्तु के लिए एक ही मान वापस करना चाहिए, यही कारण है कि यह आमतौर पर समझा जाता है कि आप एक हैशबल ऑब्जेक्ट को म्यूट नहीं करते हैं। उदाहरण के लिए, एक विकल्प हो सकता है:

class T(object): 
    #<snip> ... 

    def __hash__(self): 
     return hash(self.value) 

    #... </snip> 

समझ के साथ कि self.value वस्तु के जीवन के लिए नहीं बदल सकते हैं के साथ। (ध्यान दें, मैं दावा नहीं करते कि एक अच्छा विकल्प है वास्तविक हैश आप का उपयोग वास्तव में अपने वास्तविक आवेदन पर निर्भर है।) अब


क्यों - सेट (और dicts) के पीछे जादू और अद्भुत प्रदर्शन यह है कि वे हैश पर भरोसा करते हैं। असल में, प्रत्येक हैशबल ऑब्जेक्ट को "अद्वितीय" (एक परिपूर्ण दुनिया में) संख्या में बदल दिया जाता है। पायथन उस "अद्वितीय" संख्या को लेता है और इसे एक सरणी अनुक्रमणिका में बदल देता है जिसका उपयोग ऑब्जेक्ट पर एक हैंडल प्राप्त करने के लिए किया जा सकता है (यहां जादू को समझाना थोड़ा मुश्किल है, लेकिन इस चर्चा के लिए यह महत्वपूर्ण नहीं है)। तो, "सरणी" (आमतौर पर एक टेबल कहा जाता है) में अन्य सभी ऑब्जेक्ट्स की तुलना करके किसी ऑब्जेक्ट की तलाश करने के बजाय - एक महंगा ऑपरेशन, यह जानता है कि हैश वैल्यू (सस्ता) के आधार पर ऑब्जेक्ट को कहां देखना है । डिफ़ॉल्ट रूप से, उपयोगकर्ता परिभाषित वस्तुओं को उनके id (स्मृति पता) द्वारा धोया जाता है। जब आप xx सेट बनाते हैं, तो पाइथन id एस ऑब्जेक्ट्स को देखता है और उन्हें अपने आईडी के आधार पर रखता है। अब जब आप xx.issubset(yy) करते हैं, अजगर xx और चेक में आईडी के सभी पर लग रहा है अगर वे yy में सभी कर रहे हैं देखने के लिए। लेकिन उनमें से कोई भी yy में हैं क्योंकि वे सभी अद्वितीय वस्तुएं हैं (और इसलिए अद्वितीय हैश मान हैं)।

लेकिन आप कहते हैं, "क्यों xx-(yy-xx) == xx काम किया है?" अच्छा प्रश्न। चलो इसे अलग खींचें।

सबसे पहले, हम (yy - xx) है। यह एक खाली सेट रिटर्न क्योंकि फिर, xx में कोई तत्व yy में भी कर रहे हैं (वे सभी विभिन्न मूल्यों के लिए हैश बाद से वे सभी अद्वितीय id रों है)। तो तुम सच में

xx - set([]) == xx 

जो बहुत स्पष्ट क्यों कि True है होना चाहिए कर रहे हैं।

+0

फिर समझाएं कि उसे इसे कैसे ठीक करना चाहिए। – JBernardo

+0

@ जेबेर्नर्डो - इसे ठीक करना एक और कहानी है। ओपी को किसी भी तरह '__hash__' ओवरराइड करने की आवश्यकता है। लेकिन उचित '__hash__' चुनना वास्तव में इस बात पर निर्भर करता है कि इसका क्या उपयोग किया जा रहा है। – mgilson

+0

हां, उसे बताओ। – JBernardo

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