使用 Python 输出 YAML:格式不正确,输入中没有列表

Outputting YAML with Python: incorrect formatting without lists in input

我正在尝试从 Python 字典创建 YAML。到目前为止,我已经尝试了 PyYAML 和 ruamel.yaml 并且都具有相同的结果:如果输入字典不包含列表,则输出格式不正确。

脚本如下:

from ruamel import yaml
import sys

yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'armament': ['photon torpedoes','phasers'], 'number': 1701}, sys.stdout)
print('\n')
yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'number': 1701}, sys.stdout)

这是输出:

armament: [photon torpedoes, phasers]
class: Galaxy
name: Enterprise
number: 1701

{class: Galaxy, name: Enterprise, number: 1701}

所需的输出是第二个 YAML 转储的格式应与第一个相同。这是怎么回事?

这在 documentation 中关于如何进行一致输出的说明:

yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'number': 1701},
  sys.stdout,
  default_flow_style=False) # <- the important parameter

class: Galaxy
name: Enterprise
number: 1701

您正在使用旧样式 API 并且默认输出 any leaf 流式节点。在你的情况下 list/sequece [photon torpedoes, phasers] 和你的秒转储(根级别 叶节点)。


假设您不仅想要解释为什么会发生这种情况,还想知道如何改变这种行为,使用新的 API,使用 ruamel.yaml.YAML 的实例,默认是一切都是流式的,包括所有叶节点:

from ruamel.yaml import YAML
import sys

yaml = YAML()

yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'armament': ['photon torpedoes','phasers'], 'number': 1701}, sys.stdout)
print()
yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'number': 1701}, sys.stdout)

给予:

name: Enterprise
class: Galaxy
armament:
- photon torpedoes
- phasers
number: 1701

name: Enterprise
class: Galaxy
number: 1701

还是不是你想要的:-)

您现在有两个选项来获取您指定的内容:第一个转储为叶节点流样式,第二个为叶节点块样式。

第一个是让 default_flow_style 集的一个实例用于第一个转储和 "normal" 一个用于第二个转储:

from ruamel.yaml import YAML
import sys

yaml = YAML()

yaml.default_flow_style = None
yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'armament': ['photon torpedoes','phasers'], 'number': 1701}, sys.stdout)
print()
yaml = YAML()
yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'number': 1701}, sys.stdout)

给出:

name: Enterprise
class: Galaxy
armament: [photon torpedoes, phasers]
number: 1701

name: Enterprise
class: Galaxy
number: 1701

第二个选项是在对象上显式设置流样式 你想作为序列输出。因此你必须创建一个 ruamel.yaml.comments.CommentedSeq实例,正常使用 加载时保留flow/block-style、评论等:

from ruamel.yaml import YAML, comments
import sys

yaml = YAML()

armaments = comments.CommentedSeq(['photon torpedoes','phasers'])
armaments.fa.set_flow_style()
yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'armament': armaments, 'number': 1701}, sys.stdout)
print()
yaml.dump({'name': 'Enterprise', 'class': 'Galaxy', 'number': 1701}, sys.stdout)

这也给出了:

name: Enterprise
class: Galaxy
armament: [photon torpedoes, phasers]
number: 1701

name: Enterprise
class: Galaxy
number: 1701

第二个选项当然可以让你更好地控制(还有一个 CommentedMap) 可以在数据层次结构的所有级别上拥有这些对象,而不仅仅是在集合的叶子上。


请注意,从具有您想要的格式的 YAML 文件加载所需输出时,您不必经历任何这些滑稽动作。在那种情况下, dict resp。类似实例的列表是使用正确的 flow/block-style 创建的,因此当仅 changing/adding 一个值并转储时,输出不会意外更改。