直接用 yaml.dump() 有风险,因默认会将 datetime、set 等转为 !!python/tuple 等危险标签,跨语言读取失败或触发代码执行;safe_dump() 虽禁用标签但遇特殊类型仍报错,需预处理或自定义 representer 并显式指定 utf-8 编码。

为什么直接用 yaml.dump() 有风险
因为默认情况下 yaml.dump() 会把 Python 的内置类型(如 datetime、set、tuple)或自定义对象原样转成 YAML 标签(如 !!python/tuple),这种输出在跨语言读取时会被拒绝,甚至反序列化时可能执行任意代码(尤其搭配 yaml.load() 和不安全的 loader)。你写进去的数据,别人读不出来;更糟的是,别人用错误方式读取还可能被利用。
用 yaml.safe_dump() 是底线,但还不够
yaml.safe_dump() 确实禁用了危险标签,但它仍会抛出异常——比如遇到 datetime 或 Decimal 就直接报 RepresenterError。它只“安全”在不执行代码,不“友好”在不帮你处理常见类型。
- 必须预处理字典:把
datetime转成str,Decimal转成float或str,bytes解码或 base64 编码 - 避免用
default_flow_style=False以外的格式参数,否则嵌套深时可读性骤降 - 显式指定
allow_unicode=True,否则中文会变成\u4f60\u597d - 写入文件时务必用
encoding='utf-8',否则 Windows 上容易乱码
推荐做法:封装一个带类型适配的 dump 函数
不要每次手动转换,写一个复用函数,覆盖最常踩坑的类型:
import yaml
from datetime import datetime
from decimal import Decimal
<p>def safe_yaml_dump(data, stream=None):
def _representer(dumper, data):
if isinstance(data, datetime):
return dumper.represent_scalar('tag:yaml.org,2002:str', data.isoformat())
elif isinstance(data, Decimal):
return dumper.represent_scalar('tag:yaml.org,2002:float', str(data))
elif isinstance(data, bytes):
return dumper.represent_scalar('tag:yaml.org,2002:str', data.decode('utf-8', errors='replace'))
elif isinstance(data, set):
return dumper.represent_sequence('tag:yaml.org,2002:seq', list(data))
return dumper.represent_data(data)</p><pre class="brush:python;toolbar:false;">yaml.add_representer(object, _representer, Dumper=yaml.SafeDumper)
return yaml.dump(data, stream, Dumper=yaml.SafeDumper,
allow_unicode=True, default_flow_style=False, sort_keys=False)使用示例:
data = { 'name': '张三', 'created_at': datetime.now(), 'price': Decimal('29.99'), 'tags': {'python', 'yaml'} } with open('config.yaml', 'w', encoding='utf-8') as f: safe_yaml_dump(data, f)
别忽略 YAML 版本和 PyYAML 安装方式的影响
PyYAML 5.1+ 默认使用 Cython 加速,但某些环境(如 Alpine Linux)没装 libyaml-dev 就会回退到纯 Python 实现,性能差且偶尔行为不一致。更重要的是:pip install pyyaml 安装的是最新版,而新版(6.0+)已移除 yaml.CLoader 等旧接口,如果你的项目文档还写着“用 CLoader 提速”,那得同步更新写法。
- 生产环境建议锁版本:
pyyaml>=5.4, - 如果要用
SafeLoader读取,dump 时也必须用SafeDumper,二者语义要对齐 - 避免用
yaml.dump_all()处理单个字典——它会加---分隔符,导致非预期的多文档结构
真正麻烦的不是语法,是那些没报错但悄悄丢数据的类型转换,比如 None 变成 ~、True 变成 true(小写),这些在弱类型语言里可能引发逻辑偏差。动手前先确认下游系统怎么解析 YAML 的布尔/空值。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











