Peter
Peter

Reputation: 13505

Globally Make Python Dictionaries Ordered

I want to be able to globally make dictionaries ordered.

I often find myself writing code like this:

things_to_evaluate = {
    'thing 1': lambda: Thing(property = 'a'), 
    'thing 2': lambda: Thing(property = 'b'), 
    ...
    }

...

for k, v in things_to_evaluate.iteritems():
     thing = v()
     result[k] = thing.process(something)

In my case, the dictionary syntax is a convenient way to specify a bunch of experiments I want to try. Now, I'd like to actually have the results appear in the order I specified them.

I know that this is a terrible thing to want, and I know about hashing and unordered collections and the existence of OrderedDict and everything.

Still, it would be nice if I had the option to just for my own convenience, with one line of code, override some primitive function and make it so all dicts were ordered, consequences be damned.

So, does anyone know of a way to do this?

Upvotes: 1

Views: 73

Answers (2)

Blckknght
Blckknght

Reputation: 104762

If order is important use a list rather than a dictionary. You might not need the keys at all!

If you do need the key, you can make your list contain 2-tuples (key-value pairs). The list and tuple literal syntax can do this for you without any hacking of the system internals:

things_to_evaluate = [
    ('thing 1', lambda: Thing(property = 'a')), 
    ('thing 2', lambda: Thing(property = 'b')),
    ...
    ]

...

for k, v in things_to_evaluate:
    thing = v()
    result.append((k, thing.process(something)))

Upvotes: 2

abarnert
abarnert

Reputation: 365905

You can't do this, at least not without hacking up the source code to your favorite Python implementation and rebuilding it. (And, if your favorite implementation is CPython, this will be a huge amount of work, because OrderedDict not only isn't a builtin, it doesn't even have a C implementation—although that might change in 3.5.)

You can, of course, rebind the name dict to collections.OrderedDict, either globally (within your module) or super-globally (within builtins), but that isn't going to affect literal dictionary displays, dictionary comprehensions, builtin code that returns dictionaries (which includes things like the type function that constructs class and object __dict__ and the interpreter code that handles **kwargs), etc.

You could invent your own way of writing OrderedDict displays and comprehensions, and use an import hook with an AST transformer to convert them into calls to the OrderedDict constructor. I believe OrderedDict displays are one of the samples that comes with MacroPy, and it shouldn't be too hard to expand that to handle comprehensions as well. But without something like that, the best you're going to do is either:

from collections import OrderedDict as o

things_to_evaluate = o(
    ('thing 1', lambda: Thing(property = 'a')), 
    ('thing 2', lambda: Thing(property = 'b')), 
    ...
    )

… or:

def o(*args):
    return OrderedDict(zip(args[::2], args[1::2]))

things_to_evaluate = o(
    'thing 1', lambda: Thing(property = 'a'),
    'thing 2', lambda: Thing(property = 'b'),
    ...
    )

Upvotes: 5

Related Questions