एक अजगर को संशोधित करते हुए उस पर ध्यान केंद्रित करते हुए तानाशाह


87

मान लें कि हमारे पास पायथन शब्दकोश है d, और हम इसे इस तरह से देख रहे हैं:

for k,v in d.iteritems():
    del d[f(k)] # remove some item
    d[g(k)] = v # add a new item

( fऔर gसिर्फ कुछ ब्लैक-बॉक्स रूपांतरण हैं।)

दूसरे शब्दों में, हम dउपयोग करते समय पुनरावृति करते हुए वस्तुओं को जोड़ने / हटाने का प्रयास करते हैं iteritems

क्या यह अच्छी तरह से परिभाषित है? क्या आप अपने उत्तर का समर्थन करने के लिए कुछ संदर्भ प्रदान कर सकते हैं?

(यह बहुत स्पष्ट है कि इसे कैसे ठीक किया जाए अगर यह टूट गया है, तो यह वह कोण नहीं है जिसके बाद मैं हूं।)




मैंने ऐसा करने की कोशिश की है और ऐसा लगता है कि यदि आप प्रारंभिक तानाशाही को अपरिवर्तित छोड़ देते हैं - जैसे कि उन्हें हटाने के बजाय किसी भी कुंजी / मान को बदल दें तो यह कोड अपवाद नहीं फेंक देगा
Artiom Rudzenka

मैं इस बात से असहमत हूं कि इस विषय को खोजने वाले (स्वयं सहित) के लिए "यह स्पष्ट है कि अगर यह टूट गया है तो इसे कैसे ठीक किया जाए", और मैं चाहता हूं कि स्वीकृत उत्तर कम से कम इस पर छुआ हो।
एलेक्स पीटर्स

जवाबों:


53

यह स्पष्ट रूप से पायथन डॉक पेज ( पायथन 2.7 के लिए ) पर उल्लिखित है

iteritems()शब्दकोश में प्रविष्टियों को जोड़ने या हटाने का उपयोग करते समय RuntimeErrorसभी प्रविष्टियों पर पुनरावृति करने या विफल करने के लिए उठा सकते हैं।

इसी तरह पायथन 3 के लिए

वही धारण करता है iter(d), d.iterkeys()और d.itervalues(), मैं यह कहूँगा कि जहाँ तक यह होता है for k, v in d.items():(मुझे ठीक से याद नहीं है कि क्या forकरता है, लेकिन अगर कार्यान्वयन कहा जाता है तो मुझे आश्चर्य नहीं होगा iter(d))।


48
मैं खुद को इस बात के लिए शर्मिंदा करूंगा कि मैंने बहुत कोड स्निपेट का इस्तेमाल किया है। यह सोचकर कि जब से मुझे RuntimeError नहीं मिली, मुझे लगा कि सब कुछ अच्छा है। और यह कुछ समय के लिए था। एनली रिटेंटिव यूनिट टेस्ट मुझे थम्स अप दे रहा था और जब यह रिलीज हुआ था तब भी अच्छा चल रहा था। फिर, मुझे विचित्र व्यवहार मिलने लगा। क्या हो रहा था कि शब्दकोश में आइटम खत्म हो रहे थे और इसलिए शब्दकोश में सभी आइटम स्कैन नहीं किए जा रहे थे। बच्चे, उन गलतियों से सीखते हैं जो मैंने अपने जीवन में की हैं और बस नहीं कहना! ;)
एलन कैबरेरा

3
अगर मैं वर्तमान कुंजी में मान बदल रहा हूं (लेकिन किसी भी कुंजी को जोड़ने या हटाने के लिए नहीं?) मैं समस्याओं में चला सकता हूं? मुझे लगता है कि यह किसी भी समस्या का कारण नहीं है, लेकिन मैं जानना चाहूंगा!
गेरशोम

@GershomMaes मुझे किसी के बारे में पता नहीं है, लेकिन आप अभी भी एक माइनफील्ड में दौड़ सकते हैं, आपके लूप बॉडी को मूल्य का उपयोग करना चाहिए और इसे बदलने की उम्मीद नहीं करनी चाहिए।
राफेल सेंट-पियरे

3
d.items()पाइथन 2.7 में सुरक्षित होना चाहिए (पाइथन 3 के साथ खेल बदलता है), क्योंकि यह बनाता है कि अनिवार्य रूप से क्या की एक प्रति है d, इसलिए आप यह संशोधित नहीं कर रहे हैं कि आप क्या कर रहे हैं।
पॉल प्राइस

यह जानना दिलचस्प होगा कि क्या यह सच भी हैviewitems()
jlh

50

इस पर एलेक्स मार्टेली का वजन है

कंटेनर पर लूप करते समय कंटेनर (जैसे तानाशाह) को बदलना सुरक्षित नहीं हो सकता है। तो del d[f(k)]सुरक्षित नहीं हो सकता। जैसा कि आप जानते हैं, वर्कअराउंड का उपयोग करना है d.items()(कंटेनर की एक स्वतंत्र प्रतिलिपि पर लूप करना) d.iteritems()( बजाय उसी अंतर्निहित कंटेनर का उपयोग करता है)।

मान को किसी मौजूदा इंडेक्स पर संशोधित करना ठीक है , लेकिन नए सूचकांकों (जैसे d[g(k)]=v) में मान डालने से काम नहीं हो सकता है।


3
मुझे लगता है कि यह मेरे लिए एक महत्वपूर्ण जवाब है। बहुत सारे उपयोग के मामलों में एक प्रक्रिया होगी चीजों को डालने की और दूसरी सफाई की चीजों को ऊपर से हटाने / हटाने की ताकि d.items () कार्यों का उपयोग करने की सलाह दी जा सके। पायथन 3
कैविएट्स को समझ में

4
Python 3 केवेट्स के बारे में अधिक जानकारी PEP 469 में पाई जा सकती है, जहाँ पूर्वोक्त Python 2 तानाशाहों के शब्दार्थ समतुल्य हैं।
लियोनेल ब्रूक्स

1
"हुक्म के मौजूदा सूचकांक में मूल्य को संशोधित करना ठीक है" - क्या आपके पास इसके लिए एक संदर्भ है?
जोनाथन रेइनहार्ट

1
@JonathonReinhart: नहीं, मेरे पास इसके लिए कोई संदर्भ नहीं है, लेकिन मुझे लगता है कि यह पायथन में बहुत मानक है। उदाहरण के लिए, एलेक्स मार्टेली एक पायथन कोर डेवलपर था और यहां इसके उपयोग को प्रदर्शित करता है
अनटुब

27

आप ऐसा नहीं कर सकते, कम से कम के साथ d.iteritems()। मैंने इसे आजमाया, और पायथन के साथ विफल हो गया

RuntimeError: dictionary changed size during iteration

यदि आप इसके बजाय उपयोग करते हैं d.items(), तो यह काम करता है।

Python 3 d.items()में, शब्दकोश में एक दृश्य है, जैसे d.iteritems()Python 2 में। Python 3 में ऐसा करने के लिए, बजाय उपयोग के d.copy().items()। यह उसी तरह हमें शब्दकोश की एक प्रति पर पुनरावृति करने की अनुमति देगा ताकि हम उस डेटा संरचना को संशोधित करने से बच सकें, जिस पर हम पुनरावृत्ति कर रहे हैं।


2
मैंने अपने जवाब में पायथन 3 को जोड़ा।
murgatroid99

2
FYI, 2to3Py2 के d.items()लिए Py2 का शाब्दिक अनुवाद (उदाहरण के लिए उपयोग किया जाता है ) list(d.items()), हालांकि, d.copy().items()यह तुलनीय दक्षता है।
सोरेन लोर्बोर्ग

2
यदि प्रमुख वस्तु बहुत बड़ी है, तो d.copy ()। आइटम () प्रभावकारिता है?
ड्रैगनफ्लाई

11

मेरे पास Numpy सरणियों वाला एक बड़ा शब्दकोश है, इसलिए तानाशाह। ()। चाबियाँ () @ murgatroid99 द्वारा सुझाई गई बात व्यवहार्य नहीं थी (हालांकि यह काम किया)। इसके बजाय, मैंने बस keys_view को एक सूची में बदल दिया और यह ठीक काम किया (पायथन 3.4 में):

for item in list(dict_d.keys()):
    temp = dict_d.pop(item)
    dict_d['some_key'] = 1  # Some value

मुझे लगता है कि यह ऊपर के उत्तरों की तरह पायथन के आंतरिक कामकाज के दार्शनिक क्षेत्र में गोता नहीं लगाता है, लेकिन यह बताई गई समस्या का एक व्यावहारिक समाधान प्रदान करता है।


6

निम्न कोड दिखाता है कि यह अच्छी तरह से परिभाषित नहीं है:

def f(x):
    return x

def g(x):
    return x+1

def h(x):
    return x+10

try:
    d = {1:"a", 2:"b", 3:"c"}
    for k, v in d.iteritems():
        del d[f(k)]
        d[g(k)] = v+"x"
    print d
except Exception as e:
    print "Exception:", e

try:
    d = {1:"a", 2:"b", 3:"c"}
    for k, v in d.iteritems():
        del d[f(k)]
        d[h(k)] = v+"x"
    print d
except Exception as e:
    print "Exception:", e

पहला उदाहरण जी (के) को कॉल करता है, और एक अपवाद को फेंक देता है (पुनरावृति के दौरान इसका बदला हुआ आकार)।

दूसरा उदाहरण h (k) कहता है और कोई अपवाद नहीं फेंकता है, लेकिन आउटपुट:

{21: 'axx', 22: 'bxx', 23: 'cxx'}

जो, कोड को देखकर गलत लगता है - मुझे कुछ इस तरह की उम्मीद होगी:

{11: 'ax', 12: 'bx', 13: 'cx'}

मैं समझ सकता हूं कि आप क्यों उम्मीद कर सकते हैं {11: 'ax', 12: 'bx', 13: 'cx'}लेकिन 21,22,23 आपको वास्तव में क्या हुआ है के रूप में आपको सुराग देना चाहिए: आपका लूप आइटम 1, 2, 3, 11, 12, 13 के माध्यम से चला गया लेकिन दूसरे को लेने का प्रबंधन नहीं किया। नए आइटमों का दौर, क्योंकि वे उन वस्तुओं के सामने सम्मिलित हो गए हैं जिन्हें आपने पहले ही खत्म कर दिया था। h()वापसी करने के लिए बदलें x+5और आप एक और x प्राप्त करते हैं: 'axxx'आदि या 'x + 3' और आपको शानदार मिलता है'axxxxx'
डंकन

हाँ, मेरी गलती से मुझे डर है - मेरा अपेक्षित आउटपुट {11: 'ax', 12: 'bx', 13: 'cx'}जैसा आपने कहा था, इसलिए मैं इसके बारे में अपनी पोस्ट अपडेट करूँगा। किसी भी तरह से, यह स्पष्ट रूप से अच्छी तरह से परिभाषित व्यवहार नहीं है।
जुबैद

1

मुझे वही समस्या मिली और मैंने इस समस्या को हल करने के लिए निम्नलिखित प्रक्रिया का उपयोग किया।

यदि आप इस पर पुनरावृत्ति के दौरान संशोधित करते हैं तो भी पायथन सूची पुनरावृत्त हो सकती है। तो निम्नलिखित कोड के लिए यह 1 का अनंत प्रिंट करेगा।

for i in list:
   list.append(1)
   print 1

तो सूची और तानाशाही का उपयोग करके आप इस समस्या को हल कर सकते हैं।

d_list=[]
 d_dict = {} 
 for k in d_list:
    if d_dict[k] is not -1:
       d_dict[f(k)] = -1 # rather than deleting it mark it with -1 or other value to specify that it will be not considered further(deleted)
       d_dict[g(k)] = v # add a new item 
       d_list.append(g(k))

मुझे यकीन नहीं है कि अगर पुनरावृत्ति के दौरान किसी सूची को संशोधित करना सुरक्षित है (हालांकि यह कुछ मामलों में काम कर सकता है)। इस प्रश्न को उदाहरण के लिए देखें ...
रोमन

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

1

अजगर 3 आपको बस चाहिए:

prefix = 'item_'
t = {'f1': 'ffw', 'f2': 'fca'}
t2 = dict() 
for k,v in t.items():
    t2[k] = prefix + v

या उपयोग:

t2 = t1.copy()

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


0

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

मैंने निम्नलिखित दिनचर्या का निर्माण किया, जिसे jaraco.itertools में भी पाया जा सकता है :

def _mutable_iter(dict):
    """
    Iterate over items in the dict, yielding the first one, but allowing
    it to be mutated during the process.
    >>> d = dict(a=1)
    >>> it = _mutable_iter(d)
    >>> next(it)
    ('a', 1)
    >>> d
    {}
    >>> d.update(b=2)
    >>> list(it)
    [('b', 2)]
    """
    while dict:
        prev_key = next(iter(dict))
        yield prev_key, dict.pop(prev_key)

डॉकस्ट्रिंग उपयोग को दर्शाता है। यह फ़ंक्शन d.iteritems()वांछित प्रभाव के लिए ऊपर की जगह इस्तेमाल किया जा सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.