Search code examples
pythonpython-2.7dictionaryordereddictionary

How to unpack dictionary in order that it was passed?


This is the following problem:

main_module.py

from collections import OrderedDict
from my_other_module import foo

a = OrderedDict([
    ('a', 1),
    ('b', 2),
    ('c', 3),
    ('d', 4),
    ])

foo(**a)

my_other_module.py

def foo(**kwargs):
    for k, v in kwargs.items():
        print k, v

When i run main_module.py I'm expecting to get printout with the order I specified:

a 1
b 2
c 3
d 4

But instead I'm getting:

a 1
c 3
b 2
d 4

I do understand that this has something to do with the way ** operator is implemented and somehow it looses order how dictionary pairs are passed in. Also I do understand that dictionaries in python are not ordered as lists are, because they're implemented as hash tables. Is there any kind of 'hack' that I could apply so I get the behaviour that is needed in this context?

P.S. - In my situation I can't sort the dictionary inside foo function since there are no rules which could be followed except strict order that values are passed in.


Solution

  • By using **a you're unpacking the ordered dictionary into an argument dictionary.

    So when you enter in foo, kwargs is just a plain dictionary, with order not guaranteed (unless you're using Python 3.6+, but that's still an implementation detail in 3.6 - the ordering becomes official in 3.7: Are dictionaries ordered in Python 3.6+?)

    You could just lose the packing/unpacking in that case so it's portable for older versions of python.

    from collections import OrderedDict
    
    def foo(kwargs):
        for k, v in kwargs.items():
            print(k, v)
    
    a = OrderedDict([
        ('a', 1),
        ('b', 2),
        ('c', 3),
        ('d', 4),
        ])
    
    foo(a)