2010-10-27 7 views
7

मेरे पास कुछ पायथन कोड है जो एक KeyError अपवाद फेंक रहा है। अब तक मैं ऑपरेटिंग वातावरण के बाहर पुन: उत्पन्न करने में सक्षम नहीं हूं, इसलिए मैं यहां एक कम परीक्षण केस पोस्ट नहीं कर सकता।"k in d" कैसे गलत हो सकता है, लेकिन "k.keys() में k" सच है?

कोड है कि अपवाद को ऊपर उठाने के इस तरह एक पाश के माध्यम से पुनरावृत्ति है:

for k in d.keys(): 
    if condition: 
     del d[k] 

del[k] लाइन अपवाद फेंकता है। मैंने इसके आसपास try/except क्लॉज जोड़ा है और यह निर्धारित करने में सक्षम है कि k in d गलत है, लेकिन k in d.keys() सत्य है।

d की कुंजी पुरानी शैली के वर्ग उदाहरणों के बाध्य तरीके हैं।

कक्षा __cmp__ और __hash__ लागू करती है, इसलिए मैं अपना ध्यान केंद्रित कर रहा हूं।

+0

ठीक है, अगर तुम अब क्या 'k' कारण समस्याएं हो रही है, क्यों तुम सिर्फ नहीं दिख रहा है कि क्या यह' d.keys में मौजूद हैं() 'और' डी' में? – SilentGhost

+1

मुझे स्पष्टीकरण दें, अगर आप पुनरावृत्ति को अनदेखा करते हैं और केवल शब्दकोश का परीक्षण करते हैं, तो वहां एक कुंजी है जिसके लिए 'k in d' सत्य है लेकिन' k.keys() में k 'गलत है? अर्थात। इस मुद्दे पर पुनरावृत्ति अप्रासंगिक है? – katrielalex

+0

क्या आप अपना '__hash__' फ़ंक्शन भी दिखा सकते हैं? – user470379

उत्तर

18

k in d.keys() प्रत्येक कुंजी के लिए iteratively समानता का परीक्षण होगा, जबकि k in d__hash__ का उपयोग करता है, इसलिए आपके __hash__ को तोड़ दिया जा सकता है (यानी यह बराबर तुलना करने वाली वस्तुओं के लिए अलग हैश देता है)।

+0

'__hash__' buildbot's buildbot.util.ComparableMixin .__ हैश__ है, जो एक हैश मान उत्पन्न करने के लिए एक उदाहरण की तुलना_attrs को देखता है। ये मूल्य समय के साथ बदल रहे थे, इसलिए ऑब्जेक्ट का हैश अपने जीवनकाल के लिए स्थिर नहीं था। –

+0

हाँ, यह '__hash__' तोड़ने का एक और तरीका है। लेकिन फिर ऑब्जेक्ट को एक शब्दकोश कुंजी के रूप में उपयोग करने के लिए भी समझ में नहीं आता है। – adw

+0

हाँ, यह मेरा कोड नहीं है जो ऑब्जेक्ट को शब्द कुंजी (un) सौभाग्य से डाल रहा है। –

4

d आइटम हटाना नहीं है, जबकि इस पर पुनरावृत्ति, कुंजी आप एक सूची में हटाना चाहते हैं की दुकान और एक अन्य पाश में उन्हें हटा दें:

deleted = [] 
for k in d.keys(): 
    if condition: 
     deleted.append(k) 
for k in deleted: 
    del d[k] 
+2

वह 'd' से अधिक पुनरावृत्ति नहीं कर रहा है, वह' d.keys से अधिक पुनरावृत्ति है() 'सूची – SilentGhost

+0

@SilentGhost अगर चाबियाँ आलसी लोड (जो मुझे लगता है वे कर रहे हैं लेकिन इस समय इस बात की पुष्टि नहीं कर सकते हैं) कर रहे हैं तो यह इस में प्रभावी ढंग से एक ही बात है संदर्भ। – Davy8

+0

@ क्या आप आलसी लोड मतलब है? यह एक सूची है। – SilentGhost

-1

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

आप d.pop(k, None) का उपयोग कर सकते हैं, जो k या None पर मैप किए गए मान को वापस कर देगा, यदि k मौजूद नहीं है। यह KeyError समस्या से बचाता है।

संपादित करें: स्पष्टीकरण के लिए, अधिक प्रेत डाउनमोड्स को रोकने के लिए (नकारात्मक प्रतिक्रिया के साथ कोई समस्या नहीं, केवल इसे रचनात्मक बनाएं और एक टिप्पणी छोड़ दें ताकि हम संभावित रूप से सूचनात्मक चर्चा कर सकें - मैं यहां सीखने के साथ-साथ सहायता भी कर रहा हूं):

यह सच है कि इस विशेष स्थिति में यह में गड़बड़ नहीं करना चाहिए। मैं इसे एक संभावित मुद्दे के रूप में ला रहा था, क्योंकि यदि वह प्रोग्राम के दूसरे हिस्से में एक ही तरह की कोडिंग योजना का उपयोग कर रहा है, जहां वह नहीं है तो वह डेटा संरचना का इलाज कैसे कर रहा है, इस बारे में सावधान/भाग्यशाली है, ऐसी समस्याएं उत्पन्न हो सकती हैं । वह एक शब्दकोश का भी उपयोग नहीं कर रहा है, बल्कि एक वर्ग जो कुछ तरीकों को लागू करता है ताकि आप इसे उसी तरह से इलाज कर सकें।

+4

नहीं, यह सच नहीं है - यदि आप 'd.keys() 'में' k' के लिए केवल' del d [k] 'हैं, तो आप कभी भी कुंजी को दो बार नहीं हटाएंगे, क्योंकि कुंजी अद्वितीय हैं। – katrielalex

+1

सब कुछ मानना ​​है कि उसके ऊपर यह है, चाबियाँ एक शब्दकोश में अद्वितीय हैं, और वह केवल प्रति पुनरावृत्ति के बाद कुंजी को हटा देता है, इसलिए वह कुंजी को हटा नहीं रहा है जिसे वह पहले ही हटा चुका है। – user470379

+0

वैसे हाँ, यह सच है कि इस विशेष स्थिति में इसे गड़बड़ नहीं करना चाहिए। मैं इसे एक संभावित मुद्दे के रूप में ला रहा था। वह एक शब्दकोश का भी उपयोग नहीं कर रहा है, बल्कि एक वर्ग जो कुछ तरीकों को लागू करता है। – nearlymonolith

5

क्या, टूटा हुआ है हित के लिए की सरल उदाहरण:

>>> count = 0 
>>> class BrokenHash(object): 
...  def __hash__(self): 
...    global count 
...    count += 1 
...    return count 
... 
...  def __eq__(self, other): 
...    return True 
... 
>>> foo = BrokenHash() 
>>> bar = BrokenHash() 
>>> foo is bar 
False 
>>> foo == bar 
True 
>>> baz = {bar:1} 
>>> foo in baz 
False 
>>> foo in baz.keys() 
True 
+2

यह कभी भी लिखा गया सबसे पैथोलॉजिकल पायथन हो सकता है ... – katrielalex

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