【问题标题】:Creating a yaml file with aliases through PyYAML通过 PyYAML 创建带有别名的 yaml 文件
【发布时间】:2015-06-18 15:45:58
【问题描述】:

我需要创建一个如下格式的yaml文件:

imager: &imager
  type: "detector"
  half_angle: 75 degrees
  max_distance: 23000 meters
ownship: &ownship
  origin: [11,11,5]
  type: "uav"

vehicles:
  - <<: *ownship
  name: "uav1"
  origin: [35.69257148103399 degrees, -117.689417544709 degrees, 5500]
  sensors:
    - <<: *imager
      name: "imager1"

我将所有特定数据都存储在 Python 类中,所以我想我会使用 PyYAML 让事情变得简单。然而,当我去阅读文档时,我没有看到如何使用 PyYAML 处理别名。这个功能是否存在,还是我应该继续制作自己的 yaml 编写器?

【问题讨论】:

  • 我更新了我的答案,因为我的 ruamel.yaml 库(它具有 PyYAML 功能的超集)现在能够在不丢失合并和锚/参考信息的情况下往返此文件。从头开始创建比较困难,但是您应该能够轻松地从模板 YAML 文件开始,读入并保存它。
  • 我在一个类似的问题上发布了这个答案stackoverflow.com/a/36295979/150050

标签: python yaml alias pyyaml cross-reference


【解决方案1】:

首先,您指定的文件不是正确的 YAML。它不会读入,因为这里:

- <<: *ownship
name: "uav1"

您将顺序元素和映射元素并置,这是不允许的。如果您从第一行中删除 -,您将获得正确的 YAML 文件:

imager: &imager
  type: "detector"
  half_angle: 75 degrees
  max_distance: 23000 meters
ownship: &ownship
  origin: [11,11,5]
  type: "uav"

vehicles:
  - <<: *ownship
  name: "uav1"
  origin: [35.69257148103399 degrees, -117.689417544709 degrees, 5500]
  sensors:
    - <<: *imager
      name: "imager1"

无法使用 PyYAML 生成。

PyYAML 确实支持用于读写的锚点和引用。它确实支持merge key operator&lt;&lt; 进行阅读。但不支持合并操作符的写法。

这需要比较不同的字典,确定是否有任何字典是另一个字典的完整子集(一个字典的所有键和值都在另一个字典中),然后在子集上制作一个锚点,并在编写其他字典(而不是在子集中写键)。 PyYAML 中没有这样的代码可以这样做,因为它比在 PyYAML 支持的共享复杂对象(dictlist 等)上使用锚点和引用要复杂得多。

我的ruamel.yaml 具有 PyYAML 功能的超集,从 0.10 版本开始支持此类数据的往返。它在第一次往返时做了一些“标准化”:

imager: &imager
  type: detector
  half_angle: 75 degrees
  max_distance: 23000 meters
ownship: &ownship
  origin: [11, 11, 5]
  type: uav
vehicles:
  <<: *ownship
  name: uav1
  origin: [35.69257148103399 degrees, -117.689417544709 degrees, 5500]
  sensors:
  - <<: *imager
    name: imager1

很容易读入该 YAML 并操作生成的数据结构,然后将其写出。键的分配在您引用的字典上完成,如果在引用的字典中不可用,则从第一个合并的字典中透明地检索值。

从头开始创建这样一个结构然后转储它更加困难,因为没有支持例程通过比较字典之间的键/值来创建合并(目前)。

【讨论】:

  • ruamel.yaml 是否像 PyYAML 一样支持自定义加载器和自定义演示器?目前我需要能够保留元素的顺序(因此我需要一个自定义的 OrderedDict 加载器)、一致的引用表示以及保留合并、锚点和引用运算符。
  • @skeletalbassman 是的,它对加载器/演示器具有相同的设置。来源差别不大。我不确定您对“一致引用的表示”的确切解释是什么(我看到人们希望在同一个映射中不引用键标量而引用值标量)。如果事情没有立即按预期工作,请尝试并在Stack Overflow 上发布问题。
【解决方案2】:

如果你的 python 数据结构包含对同一个对象的多个引用,看起来 PyYAML 做的事情是正确的。例如,考虑一下:

>>> a = {'name': 'bob', 'office': '100'}
>>> b = {'president': a, 'vice-president': a}
>>> b
{'president': {'name': 'bob', 'office': '100'}, 'vice-president': {'name': 'bob', 'office': '100'}}
>>> import yaml
>>> print yaml.dump(b)
president: &id001 {name: bob, office: '100'}
vice-president: *id001

PyYAML 已识别出 'president' 和 'vice-president' 键的值是对同一对象的引用,并创建了一个别名并适当地使用它。

【讨论】:

  • 共享对象不是问题,写入时根本不支持合并键(&lt;&lt;)。
  • 啊,对不起。我错过了你想要的;您明确询问了别名。
猜你喜欢
  • 2017-12-08
  • 2020-02-16
  • 2011-11-07
  • 2017-12-15
  • 2016-06-01
  • 2021-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多