【问题标题】:Yaml dump for python lists uses inline format instead of hypen + space用于 python 列表的 Yaml 转储使用内联格式而不是连字符 + 空格
【发布时间】:2016-06-29 00:10:47
【问题描述】:

我有一个 python 有序字典,例如,

from collections import OrderedDict 
a = OrderedDict()
a['name'] = 'hello'
a['msgs'] = ['hello', 'world']

我将其转换为 YAML 语法,

import yaml
with open("b.yaml", 'w') as stream:
  stream.write(yaml.dump(a))

打印出来,

!!python/object/apply:collections.OrderedDict
- - [name, hello]
  - - msgs
    - [hello, world]

然而,我希望 YAML 格式更简单,

name : hello
msgs:
   - hello
   - world

如何强制 YAML 使用 hypen + space 表示法而不是像 [a,b,c,d] 表示法那样的 JSON 打印列表项?

为什么 PyYAML 将 Ordered dict 项打印为 [name, hello] 而不是 name : hello

【问题讨论】:

    标签: python yaml pyyaml


    【解决方案1】:

    您的问题将一些事情混淆在一起。从您的初始示例开始,您需要显式编码将您的a = {...} 转换为OrderedDict。撇开这一点不谈,这是您的预期输出:

    >>> a = {
    ...   "name" : 'hello',
    ...   "msgs" : ['hello', 'world']
    ... }
    >>> print(yaml.dump(a))
    msgs: [hello, world]
    name: hello
    

    这不是您想要的。如果您专门阅读了有关此问题的FAQ,您会发现将default_flow_style 传递给dump 将产生您想要的结果

    >>> print(yaml.dump(a, default_flow_style=False))
    msgs:
    - hello
    - world
    name: hello
    

    至于为什么OrderedDict会这样出来,这在文档的YAML tags and Python types部分有讨论。简而言之,这是考虑到 Python 的 pickle 协议而完成的,并且由于 OrderedDict 在内部是 lists(其中 lists 是有序的;dicts 根据定义是无序的),它得到了类似列表的表示.

    【讨论】:

    • 请注意,您文件中的键未按预期顺序排列,如果将该文件检入修订控制系统,可能会导致问题。此外,序列的缩进也不像 OP 预期的那样,而是与 msgs 键对齐。
    【解决方案2】:

    如果您没有阅读 YAML 规范,您会认为 YAML 文件中的映射是有序的,因为 YAML 文件中的文本表示是有序的。不幸的是,这种直观的假设是错误的,YAML 1.2 明确指出这[应该被解释为] 键:值对无序集。

    如果您使用映射并加载/更改/转储它们,这当然使得使用 diff 之类的工具比较 YAML 文件几乎是不可能的,并且使得将此类文件检查到修订控制系统会导致虚假的额外修订,这些修订在语义上是相同,但在语法上不同。

    我还出于其他原因(YAML 1.2 兼容性而不是旧的 1.1 规范、保留 cmets、错误修复)着手改进 PyYAML,但如果您使用其 round_trip_dumpruamel.yaml 也会将排序保留为映射:

    import ruamel.yaml
    from ruamel.yaml.comments import CommentedMap as OrderedDict
    
    a = OrderedDict()
    a['name'] = 'hello'
    a['msgs'] = ['hello', 'world']
    
    with open("b.yaml", 'w') as stream:
        ruamel.yaml.round_trip_dump(a, stream, indent=5, block_seq_indent=3)
    

    这会给你一个文件b.yaml 的内容:

    name : hello
    msgs:
       - hello
       - world
    

    正是您所期望的。

    请注意,我在流中传递给round_trip_dump,如果您使用 PyYAML,您也应该这样做,因为它更有效。
    您需要使用 CommentedMap,它只是 OrderedDict/ordereddict 周围的一个薄包装,允许保存 cmets 等。
    默认indent 为 2,block_seq_indent 为 0。

    如果您使用round_trip_dump 加载文件,您将再次获得一个 CommentedMap,其中键的顺序将与预期一致。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-24
      • 2020-11-16
      • 2017-12-02
      • 2021-11-07
      • 2014-07-06
      相关资源
      最近更新 更多