简体   繁体   中英

RuntimeError: OrderedDict mutated during iteration

I'm relatively new to python3 & am trying to iterate over a preexisting OrderedDict() to remove entries with None as the value. In python2 this wasn't a problem, but it's my understanding that the removal of dict.iteritems() (etc...) was due to some changes in the way dict.items() is returned.

I reeeeeeeeeeally want to avoid copying the dictionary...

I'm going to be doing (potentially hundreds of) thousands of these & I don't want to double the amount of memory I'm using just to remove null entries from an OrderedDict .

Here's the code that's throwing the error:

class DefaultHeaders(OrderedDict):
    def __init__(self, loop=None):
        super(DefaultHeaders, self).__init__()

        self['User-Agent'] = "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:16.0.1) Gecko/20121011 Firefox/16.0.1" # <--(dummy User-Agent header for consistent response-format)
        self['X-Search-ClientIP'] = gethostbyname(gethostname())                                                 
        self['X-MSEdge-ClientID'] = None
        self['Accept'] = None
        self['Accept-Language'] = None
        self['X-Search-Location'] = None

        self._clean1() # <--raises error
        # self._clean2() # <--raises error
        # self._clean3() # <--raises error

    def _clean1(self):
        for k, v in self.items():
            if k in ('count', 'offset'):
                pass
            elif not v: del self[k]

    def _clean2(self):
        for k, v in list(self.items()):
            if k in ('count', 'offset'):
                pass
            elif not v: del self[k]


    def _clean3(self):
        _iter_this = list(self.items())
        for k, v in _iter_this:
            if k in ('count', 'offset'):
                pass
            elif not v: del self[k]

And here's the error I'm getting:

...
    for k, v in self.items():
RuntimeError: OrderedDict mutated during iteration

Process finished with exit code 1

(>_<) i feel a little dumb but that's not new lol. Thanks to everyone who posted answers. Here's what I've got now:

def _clean(self):
    for k in list(self.keys()):
        if k in ('count', 'offset'):
            pass
        elif not self[k]:
            del self[k]

Also I realized copying isn't an option. I'd need to reassign self & creating a new instance of my class calls _clean() producing infinite recursion.

What about iterating the dictionary with an index?:

    def _clean4(self):
        i = 0

        while i < len(self):
            if self.keys()[i] not in ('count', 'offset') and not self[self.keys()[i]]:
                del self[self.keys()[i]]
            else:
                i = i + 1

您是否尝试过:

[ordered_dict.pop(k) for k in ordered_dict if k not in ['count', 'offset'] or ordered_dict[k] == None]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM