简体   繁体   中英

Make ordered dict default?

Is it possible to make default dict literal to create ordered dicts not unordered ones?

I would like to type complex nested configs like:

config = {
   'train': {
       'speed': 0.001,
       'initial_values': [1, 2, 3]
   },
   'model': {
...
   }
}

and an idea to write a mess of brackets

config = OrderedDict([(
    'train', OrderedDict([(
       'speed', 0.001), (
       'initial_values', [1, 2, 3])]),(
    'model', OrderedDict([(
...

is absolutely unaplicable.

Please no phylosophy about why my wish is bad.


Ok, currently I would write somethong like:

def od(*args):
   return OrderedDict([(args[i], args[i+1]) for i in range(0, len(args), 2)])

config = od(
    'train', od(
        'speed', 0.001,
        'initial_values', [1, 2, 3]
     ),
     'model', od(
    ...
     )
)

No, you can't alter Python syntax, not without altering the CPython source code and recompiling, but then it would not be Python any more.

The best you can do is to upgrade to Python 3.6 or newer , where dictionaries retain insertion order by default . If you must have the full OrderedDict feature set (reordering, reversing, dict views with ordering), then convert those regular dictionaries to OrderedDict objects after the fact:

from collections import OrderedDict
from functools import singledispatch

@singledispatch
def to_ordered_dict(d):
    """Convert dictionaries to OrderedDict objects, recursively

    Assumes you want to use current dictionary iteration order; in Python 3.7
    and newer that's the same as insertion order (or earlier if on PyPy, or 
    when using CPython, 3.6 and newer).

    """
    return d

@to_ordered_dict.register(dict)
def _dict(d):
    return OrderedDict(
        (to_ordered_dict(k), to_ordered_dict(v))
        for k, v in d.items()
    )

@to_ordered_dict.register(list)
@to_ordered_dict.register(tuple)
def _sequence(s):
    return type(s)(map(to_ordered_dict, s))

# add additional type registrations for other compound or container types

and then stick to using {...} notation with a config = to_ordered_dict(config) line at the end.

There's no philosophical reason why you shouldn't get to do this, but you may not do it by altering fundamental Python syntax. As mentioned elsewhere Python dictionaries can retain order after 3.6, but if you must use OrderedDict

d = OrderedDict

config = d([(...)])

You can do the same with methods like .update

Although this doesn't directly answer to your question the way you stated it, I guess you really want to have ability to process some configs. I usually prefer saving configs not in python files, but in some structured data format. So if you can admit usage of json you could do the following.

from collections import OrderedDict
import json

result = json.loads(
'''
    {
       "train": {
           "speed": 0.001,
           "initial_values": [1, 2, 3]
       },
       "model": {
            "name": "model_name",
            "wheight" : 128000
       }
    }
''', 
object_pairs_hook=lambda pairs: OrderedDict(pairs))

This should work even in python 2.7.

And if you have a dedicated file for config then you can do something like

from collections import OrderedDict
import json

with open('settings.conf', 'r') as f:
    settings_str = f.read()
    settings = json.loads(settings_str, object_pairs_hook=lambda pairs: OrderedDict(pairs))

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