PyYAML:控制yaml.load()调用的项的顺序

2024-06-17 11:59:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个yaml设置文件,它在db中创建一些记录:

setting1:
  name: [item,item]
  name1: text
anothersetting2:
  name: [item,item]
  sub_setting:
      name :[item,item]

当我使用设置3更新此文件并通过以下方式重新生成db中的记录时:

import yaml
fh = open('setting.txt', 'r')
setting_list = yaml.load(fh)
for i in setting_list:
    add_to_db[i]

每次我把它们添加到数据库时,它们的设置顺序(数据库中的id号)保持不变是非常重要的。。。seting3只是附加到yaml.load()的末尾,这样它的id就不会混淆数据库中已经存在的任何记录。。。 每次我添加另一个设置并调用yaml.load()时,记录都会以不同的顺序加载,这会导致不同的ID。我欢迎任何意见;)

编辑: 我遵循了abarnert的提示,并接受了这个要点https://gist.github.com/844388

按预期工作谢谢!


Tags: 文件nameid数据库yamldb顺序记录
3条回答

YAML规范明确指出,映射中的键顺序是一个不可依赖的“表示细节”。因此,如果您的设置文件依赖于映射,那么它已经无效,如果可能的话,最好使用有效的YAML。

当然,YAML是可扩展的,没有什么可以阻止您向设置文件添加“有序映射”类型。例如:

!omap setting1:
  name: [item,item]
  name1: text
!omap anothersetting2:
  name: [item,item]
  !omap sub_setting:
      name :[item,item]

您没有提到您正在使用的是哪个yaml模块。标准库中没有这样的模块,而且PyPI上至少有两个包提供了具有该名称的模块。不过,我猜是皮亚姆,因为据我所知这是最受欢迎的。

上面描述的扩展很容易用PyYAML解析。见http://pyyaml.org/ticket/29

def omap_constructor(loader, node):
    return loader.construct_pairs(node)
yaml.add_constructor(u'!omap', omap_constructor)

现在,代替:

{'anothersetting2': {'name': ['item', 'item'],
  'sub_setting': 'name :[item,item]'},
 'setting1': {'name': ['item', 'item'], 'name1': 'text'}}

你会得到这个:

(('anothersetting2', (('name', ['item', 'item']),
  ('sub_setting', ('name, [item,item]'),))),
 ('setting1', (('name', ['item', 'item']), ('name1', 'text'))))

当然这会给你一个tuple的键值tuple,但是你可以很容易地编写一个构造有序的dict并得到一个OrderedDict。如果需要输出和输入,还可以编写一个representer,将OrdereredDict对象存储为!omaps。

如果您真的想钩住PyYAML使其使用OrderedDict而不是dict作为默认映射,那么如果您已经在直接处理解析器对象,就很容易做到,但是如果您想坚持使用高级方便方法,就更难做到。幸运的是,上面的链接票证有一个可以使用的实现。请记住,您不再使用真正的YAML,而是一个变体,因此处理您的文件的任何其他软件都可能会崩溃。

您现在可以使用ruaml.yaml进行此操作。

来自https://pypi.python.org/pypi/ruamel.yaml

ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order

我的项目^{}是PyYAML的替代品,PyYAML将把映射加载到collections.OrderedDict,而不是常规的dict中。只需pip安装它并正常使用——在Python3和Python2上都可以。

示例演示:

>>> import oyaml as yaml  # pip install oyaml
>>> yaml.load('''setting1:
...   name: [item,item]
...   name1: text
... anothersetting2:
...   name: [item,item]
...   sub_setting:
...       name :[item,item]''')
OrderedDict([('setting1',
              OrderedDict([('name', ['item', 'item']), ('name1', 'text')])),
             ('anothersetting2',
              OrderedDict([('name', ['item', 'item']),
                           ('sub_setting', 'name :[item,item]')]))])

相关问题 更多 >