【问题标题】:Make ordered dict default?将有序字典设为默认?
【发布时间】:2019-04-26 19:12:20
【问题描述】:

是否可以使用默认的字典文字来创建有序的字典而不是无序的字典?

我想输入复杂的嵌套配置,例如:

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

还有一个写一堆括号的想法

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

绝对不适用。

请不要解释为什么我的愿望不好。


好的,目前我会写一些类似的东西:

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(
    ...
     )
)

【问题讨论】:

  • 简而言之,不...但请阅读stackoverflow.com/questions/39980323/… 了解 3.6+ 的功能以及注意事项和更多​​详细信息。
  • 使用 Python 3.6+。
  • “绝对不适用……” 为什么?
  • @RoadRunner 到许多样板代码

标签: python dictionary literals ordereddictionary


【解决方案1】:

虽然这并没有像您所说的那样直接回答您的问题,但我想您确实希望能够处理一些配置。我通常不喜欢将配置保存在 python 文件中,而是以某种结构化数据格式保存。因此,如果您可以承认使用 json,则可以执行以下操作。

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))

即使在 python 2.7 中也应该可以工作。

如果你有一个专用的配置文件,那么你可以做类似的事情

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))

【讨论】:

    【解决方案2】:

    不,您不能更改 Python 语法,除非更改 CPython 源代码并重新编译,否则它将不再是 Python。

    您可以做的最好的事情是升级到 Python 3.6 或更新版本,其中字典 retain insertion order by default。如果您必须拥有完整的 OrderedDict 功能集(重新排序、反转、带有排序的 dict 视图),那么在事后将这些常规字典转换为 OrderedDict 对象:

    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
    

    然后坚持使用{...} 表示法,并在末尾添加config = to_ordered_dict(config) 行。

    【讨论】:

    • 这不是暗示class OrderedDict(dict): 在 3.6+ 中实际上已经过时了吗?还在github.com/python/cpython/blob/3.7/Lib/collections/__init__.py
    • @usr2564301:不,它没有! OrderedDict 提供的功能不仅限于记住插入顺序。
    • 知道了!您提到的答案中的最后一段“..因为它提供了一些额外的功能”?
    【解决方案3】:

    你不应该这样做没有哲学上的原因,但你可能不会通过改变基本的 Python 语法来做到这一点。如其他地方所述,Python 字典在 3.6 之后可以保留顺序,但如果必须使用 OrderedDict

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

    你可以用.update这样的方法来做同样的事情

    【讨论】:

    • 不过,即使使用单字母别名,您也无法避免为每个键值对使用列表和元组。
    • 真的@MartijnPieters
    猜你喜欢
    • 2011-06-29
    • 2021-12-20
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-14
    相关资源
    最近更新 更多