17

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

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

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

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

每次将它们添加到数据库时,它们的设置顺序(数据库中的 id 编号)都保持相同,这一点至关重要……而 setting3 只是被附加到 yaml.load() 的末尾,这样它的 id 就不会了t混淆已经在数据库中的任何记录......目前每次我添加另一个设置并调用 yaml.load() 记录以不同的顺序加载,从而导致不同的 id。我欢迎任何想法;)

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

按预期工作谢谢!

4

5 回答 5

16

我的项目oyaml是 PyYAML 的替代品,它将加载地图collections.OrderedDict而不是常规字典。只需 pip 安装并正常使用 - 适用于 Python 3 和 Python 2。

用你的例子演示:

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

请注意,如果 stdlib 字典是顺序保留的(Python >= 3.7,CPython >= 3.6),那么oyaml将使用普通字典。

于 2018-05-09T15:44:53.200 回答
5

您现在可以为此使用ruaml.yaml

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

ruamel.yaml 是一个 YAML 解析器/发射器,支持注释的往返保存、seq/map 流样式和映射键顺序

于 2016-08-18T10:49:08.170 回答
4

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

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

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

你没有提到yaml你正在使用哪个模块。标准库中没有这样的模块,并且仅在 PyPI 上至少有两个包提供具有该名称的模块。但是,我猜它是 PyYAML,因为据我所知这是最受欢迎的。

上面描述的扩展很容易用 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'))))

当然这给了你一个tuplekey-value tuple,但是你可以很容易地写一个construct_ordereddict 并得到一个OrderedDict。如果您需要输出和输入,您还可以编写一个将OrdereredDict对象存储为s 的表示器。!omap

如果您真的想挂钩 PyYAML 以使其使用 anOrderedDict而不是 adict进行默认映射,那么如果您已经直接处理解析器对象,这很容易做到,但如果您想坚持使用高级便利方法则更加困难. 幸运的是,上面链接的票证有一个您可以使用的实现。请记住,您不再使用真正的 YAML,而是一种变体,因此任何其他处理您的文件的软件都可能并且很可能会破坏。

于 2012-11-08T22:30:27.713 回答
0

对于已知为有序字典的给定单个项目,只需制作列表中的项目并使用 collections.OrderedDict:

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

import collections
import yaml
fh = open('setting.txt', 'r')
setting_list = yaml.load(fh)

setting1 = collections.OrderedDict(list(x.items())[0] for x in setting_list['setting1'])
于 2017-07-28T00:56:53.117 回答
-2

上次我听说,PyYAML 不支持这一点,尽管修改它以接受字典或类似字典的对象作为起点可能很容易。

于 2012-11-08T22:08:57.000 回答