You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自定义PyYaml Dumper实现按类型输出非嵌套集合?

自定义PyYAML Dumper实现指定格式输出

需求说明

需要导出如下格式的YAML文件:

Strings:
  - "A very very long string"
  - "A very very long string2"
  - "A very very long string3"
  - "A very very long string4"
  - "A very very long string5"
  - "A very very long string8"
Numbers: [1,2,3,4,5,6,7,8,9]
StringsDict:
  - First: "A very very long string"
  - Second: "A very very long string8"
NumbersDict: {"First": 12, "Second": 156}

输出规则:

  • 底层仅含数字的集合(列表/字典)以单行紧凑格式输出
  • 底层包含字符串的集合(列表/字典)每个元素单独占一行
  • 嵌套集合始终以单行紧凑格式输出

实现方案

通过继承PyYAML的Dumper类,重写列表和字典的表示方法,根据集合元素类型和嵌套状态判断输出格式:

import yaml
from yaml.representer import SafeRepresenter

class CustomDumper(yaml.Dumper):
    def represent_list(self, data):
        # 判断是否为嵌套列表(父节点非根节点)
        is_nested = self.indent > self.default_flow_style_indent
        # 判断列表是否仅包含数字类型元素
        all_numbers = all(isinstance(item, (int, float)) for item in data)

        if is_nested or all_numbers:
            # 嵌套列表或纯数字列表,用单行紧凑格式
            return SafeRepresenter.represent_list(self, data)
        else:
            # 含字符串的顶层列表,用块格式逐行输出
            return self.represent_sequence('tag:yaml.org,2002:seq', data, flow_style=False)

    def represent_dict(self, data):
        # 判断是否为嵌套字典
        is_nested = self.indent > self.default_flow_style_indent
        # 判断字典值是否仅包含数字类型
        all_numbers = all(isinstance(val, (int, float)) for val in data.values())

        if is_nested or all_numbers:
            # 嵌套字典或纯数字值字典,用单行紧凑格式
            return SafeRepresenter.represent_dict(self, data)
        else:
            # 含字符串值的顶层字典,用块格式逐行输出
            return self.represent_mapping('tag:yaml.org,2002:map', data, flow_style=False)

# 注册自定义的列表和字典表示逻辑
CustomDumper.add_representer(list, CustomDumper.represent_list)
CustomDumper.add_representer(dict, CustomDumper.represent_dict)

# 测试数据
test_data = {
    "Strings": [
        "A very very long string",
        "A very very long string2",
        "A very very long string3",
        "A very very long string4",
        "A very very long string5",
        "A very very long string8"
    ],
    "Numbers": [1,2,3,4,5,6,7,8,9],
    "StringsDict": [
        {"First": "A very very long string"},
        {"Second": "A very very long string8"}
    ],
    "NumbersDict": {"First": 12, "Second": 156},
    # 验证嵌套集合格式
    "NestedExample": {
        "InnerNumList": [10, 20, 30],
        "InnerNumDict": {"X": 100, "Y": 200}
    }
}

# 导出符合要求的YAML
print(yaml.dump(test_data, Dumper=CustomDumper, default_flow_style=None, sort_keys=False))

代码说明

  1. 嵌套状态判断:通过当前缩进值与默认流格式缩进值的对比,识别嵌套集合,强制用单行格式输出。
  2. 元素类型校验:检查集合内元素(字典校验值)是否全为数字,纯数字集合采用单行紧凑格式。
  3. 格式切换逻辑:非嵌套且包含字符串的集合,使用块格式让每个元素单独占一行;其他情况使用流格式输出。
  4. 附加配置:sort_keys=False保证输出键顺序与原字典一致,default_flow_style=None让自定义逻辑主导格式选择。

内容的提问来源于stack exchange,提问作者Stein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 13:45:33