通过 PyYAML 创建带有别名的 yaml 文件

Creating a yaml file with aliases through PyYAML

我需要创建一个格式如下的 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 编写器?

如果您的 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' 键的值是对同一对象的引用,并创建了一个别名并适当地使用它。

首先你指定的文件不是正确的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 << 阅读。但是不支持合并操作符的写法

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

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

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 并操作生成的数据结构然后将其写出很容易。键的分配是在您引用的字典上完成的,如果在引用的字典中不可用,则从第一个合并的字典中透明地检索值。

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