如何在PyYaml中添加带|-块截断指示符的字面量字符串并自定义Dumper?
问题描述
我尝试从Python对象生成YAML文件,其中存在字面量字符串属性pattern = "^[0-9]+$",需要将其添加到同名节点pattern中作为块字面量,同时filter_sql_expr的布尔值True也要用带|-的块样式输出。
现有代码
import yaml class MyDumper(yaml.Dumper): def increase_indent(self, flow=False, indentless=False): return super(MyDumper, self).increase_indent(flow, False) source = {'row_filters':{'NONE':{'filter_sql_expr': True}}, 'rule_dimensions': ['completeness','conformance'], 'rules': {'VALID_CUSTOMER_ID': {'rule_type': 'REGEX', 'dimension': 'accuracy', 'params': {'pattern': "^[0-9]+$"}}}} print(yaml.dump(source, Dumper=MyDumper, default_flow_style=False,sort_keys=False,indent=2,allow_unicode=True))
实际输出YAML
row_filters: NONE: filter_sql_expr: True rule_dimensions: - completeness - conformance rules: VALID_CUSTOMER_ID: rule_type: REGEX dimension: accuracy params: pattern: ^[0-9]+$
期望输出YAML
row_filters: NONE: filter_sql_expr: |- True rule_dimensions: - completeness - conformance rules: VALID_CUSTOMER_ID: rule_type: REGEX dimension: accuracy params: pattern: |- ^[0-9]+$
核心需求
为目标节点的内容添加带块截断指示符|-的块字面量格式,确保指定内容以该格式输出。
疑问
- 如何强制指定的字符串(或布尔值转换后的字符串)使用带
|-的块样式输出? - 如何给自定义的
MyDumper类添加对应的转换逻辑?
解决方案
1. 自定义类型标记目标内容
先创建一个自定义类,用来标记需要特殊处理的内容,让YAML Dumper能识别并应用块字面量格式:
class BlockLiteral(str): pass
然后把需要转换的内容包装成这个类的实例(注意布尔值True要转成字符串,否则YAML会按原生布尔类型输出):
source = { 'row_filters': {'NONE': {'filter_sql_expr': BlockLiteral("True")}}, 'rule_dimensions': ['completeness','conformance'], 'rules': { 'VALID_CUSTOMER_ID': { 'rule_type': 'REGEX', 'dimension': 'accuracy', 'params': {'pattern': BlockLiteral("^[0-9]+$")} } } }
2. 给MyDumper添加转换方法
在自定义Dumper中注册BlockLiteral类型的转换函数,强制输出带|-的块字面量:
import yaml class MyDumper(yaml.Dumper): def increase_indent(self, flow=False, indentless=False): return super(MyDumper, self).increase_indent(flow, False) # 定义转换逻辑:用|-块样式输出内容 def represent_block_literal(dumper, data): return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|-') # 把自定义类型和转换函数绑定 MyDumper.add_representer(BlockLiteral, represent_block_literal)
3. 完整代码及测试
整合所有部分后的完整代码:
import yaml class BlockLiteral(str): pass class MyDumper(yaml.Dumper): def increase_indent(self, flow=False, indentless=False): return super(MyDumper, self).increase_indent(flow, False) def represent_block_literal(dumper, data): return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|-') MyDumper.add_representer(BlockLiteral, represent_block_literal) source = { 'row_filters': {'NONE': {'filter_sql_expr': BlockLiteral("True")}}, 'rule_dimensions': ['completeness','conformance'], 'rules': { 'VALID_CUSTOMER_ID': { 'rule_type': 'REGEX', 'dimension': 'accuracy', 'params': {'pattern': BlockLiteral("^[0-9]+$")} } } } print(yaml.dump(source, Dumper=MyDumper, default_flow_style=False,sort_keys=False,indent=2,allow_unicode=True))
运行后就能得到你期望的YAML输出,目标节点会自动带上|-块截断指示符,内容以缩进的块字面量形式展示。
补充说明
- 如果需要让所有字符串都用块字面量输出,直接把
str类型注册到转换函数即可,无需用BlockLiteral包装; style='|-'参数是核心,它指定了输出时使用带截断指示符的块字面量格式;- 布尔值必须转成字符串再包装,否则YAML会按原生布尔类型处理,无法应用块样式。
内容的提问来源于stack exchange,提问作者RoxaneFelton
相关产品推荐
相关产品推荐

