Python 处理 YAML 文件完全指南
用 Python 读写 YAML:PyYAML 基础读写、嵌套数据操作、安全加载、从对象生成 YAML、PyKwalify 校验配置文件合法性。
直接回答:PyYAML 是需要单独安装的第三方 YAML 库:safe_load 将 YAML 解析为相应 Python 数据,dump 写回;配置修改、批量生成、合法性校验都能几行搞定。 记住一条军规:永远用 safe_load,不用 load。
安装与读取
pip install pyyaml
import yaml
with open("config.yaml", encoding="utf-8") as f:
config = yaml.safe_load(f) # 也可能返回标量或空文档的 None
if not isinstance(config, dict) or not isinstance(config.get("database"), dict):
raise ValueError("配置必须包含 database 映射")
print(config["database"]["host"])
safe_load 只解析纯数据结构;旧版本默认 load 或显式不安全 Loader 可能构造任意 Python 对象;当前 PyYAML 的 load 需要显式 Loader,不能把无 Loader 调用当作当前可运行 API。对于外部配置应优先 safe_load,且仍需结构和资源限制。
YAML 与 Python 类型映射
| YAML | Python |
|---|---|
| 映射(键值) | dict |
| 序列(- 列表) | list |
| 字符串/数字/布尔 | str/int/float/bool |
| null / ~ | None |
| 日期 | datetime.date |
修改与写回
config["database"]["pool_size"] = 20
config["features"].append("new-ui")
with open("config.yaml", "w", encoding="utf-8") as f:
yaml.safe_dump(config, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
三个实用参数:allow_unicode=True(中文不转义)、sort_keys=False(保持原有键序)、default_flow_style=False(块式输出更人读)。
从零生成 YAML
deploy = {
"version": "1.0",
"services": [
{"name": "web", "replicas": 3, "ports": [80, 443]},
{"name": "worker", "replicas": 2},
],
}
with open("deploy.yaml", "w", encoding="utf-8") as f:
yaml.safe_dump(deploy, f, allow_unicode=True, sort_keys=False)
嵌套列表与字典按数据结构原样生成——批量产出 K8s 清单、CI 配置的自动化脚本就靠它。
校验:PyKwalify
先安装 pykwalify。YAML 解析检查语法,Schema 再检查结构和约束。下面的独立校验示例只允许 database 配置;真实配置若包含 features 等键,也要在 schema 中声明:
from pykwalify.core import Core
config = {"database": {"host": "localhost", "port": 5432}}
schema = """
type: map
mapping:
database:
required: True
type: map
mapping:
host: {type: str, required: True}
port: {type: int, range: {min: 1, max: 65535}}
"""
core = Core(source_data=config, schema_data=yaml.safe_load(schema))
core.validate() # 不合法直接抛异常,指明字段与原因
启动时先校验配置再初始化——"配置错误启动即报"比"运行半小时后诡异崩溃"仁慈太多。
工程实践
- 注释与格式:PyYAML dump 会丢注释。要保留注释的读写用
ruamel.yaml; - 多文档:
safe_load_all处理---分隔的多文档文件(K8s 清单常见); - 环境变量:YAML 不支持插值,常见做法是读入后应用层替换
${VAR}占位符。
常见问题(FAQ)
Q:PyYAML 和 ruamel.yaml 怎么选?
A:纯读写配置 PyYAML 通常够用;需要保留注释、格式、键序的"改写已有 YAML"场景用 ruamel.yaml。
Q:YAML 和 JSON/TOML 怎么选?
A:人写的配置选 YAML/TOML(注释友好);机器间传输常选 JSON;具体配置格式要符合消费工具的约定,Kubernetes 也可接受 JSON 清单。
Q:safe_load 真的安全吗?
A:safe_load 限制对象构造,但不是对任意不可信输入的资源隔离保证。限制输入大小、结构深度及解析时间,避免后续递归处理别名形成的共享或循环结构;必要时在受限进程处理。
官方参考
本文基于官方文档整理,未进行运行时或性能测试。示例中的业务函数、数据模型和部署地址需结合项目补全;局部片段不等同于完整生产应用。