Question

Following works for a dictionary, but not OrderedDict. For od it seems to form an infinite loop. Can you tell me why? If the function input is dict it has to return dict, if input is OrderedDict it has to return od.

def key_lower(d):
    """returns d for d or od for od with keys changed to lower case
    """
    for k in d.iterkeys():
        v = d.pop(k)
        if (type(k) == str) and (not k.islower()):
            k = k.lower()
        d[k] = v

    return d
Was it helpful?

Solution

It forms an infinite loop because of the way ordered dictionaries add new members (to the end)

Since you are using iterkeys, it is using a generator. When you assign d[k] = v you are adding the new key/value to the end of the dictionary. Because you are using a generator, that will continue to generate keys as you continue adding them.

You could fix this in a few ways. One would be to create a new ordered dict from the previous.

def key_lower(d):
     newDict = OrderedDict()
    for k, v in d.iteritems():
        if (isinstance(k, (str, basestring))):
            k = k.lower()
        newDict[k] = v
    return newDict

The other way would be to not use a generator and use keys instead of iterkeys

OTHER TIPS

As sberry mentioned, the infinite loop is essentially as you are modifying and reading the dict at the same time.

Probably the simplest solution is to use OrderedDict.keys() instead of OrderedDict.iterkeys():

for k in d.keys():
    v = d.pop(k)
    if (type(k) == str) and (not k.islower()):
        k = k.lower()
    d[k] = v

as the keys are captured directly at the start, they won't get updated as items are changed in the dict.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top