Python实用工具:PyYAML 从入门到实战,轻松搞定YAML文件读写

一、PyYAML 库概述

在Python开发过程中,配置文件的管理是项目开发中不可或缺的一环,相比于传统的INI、JSON配置文件,YAML凭借简洁易读、支持注释、可嵌套、支持列表与字典混合使用的语法优势,成为现代项目配置文件的首选格式,而PyYAML就是Python生态中专门用于解析和生成YAML文件的标准库。

PyYAML的核心工作原理是实现Python数据类型与YAML格式数据的双向转换,它可以将Python中的字典、列表、字符串、数字、布尔值、None等基础数据类型序列化为YAML格式文本,也能将YAML格式的文本或文件反序列化为Python可直接操作的数据对象,底层基于YAML 1.1规范实现解析,兼容主流YAML语法规则。

该库采用MIT License开源,允许商业与非商业项目自由使用、修改和分发。其优点是语法简洁、使用简单、兼容性强、支持复杂数据结构,缺点是解析大型YAML文件时性能略低于部分专用解析库,且存在一定的安全风险,不建议解析不可信的YAML内容。

二、PyYAML 安装方法

PyYAML作为Python第三方库,无法通过Python内置模块直接调用,需要使用pip包管理器进行安装,安装命令支持普通安装与指定版本安装,适配Windows、macOS、Linux全平台系统。

2.1 基础安装命令

打开系统命令提示符(CMD)、PowerShell或终端,直接执行以下pip命令即可完成安装:

pip install pyyaml

2.2 指定版本安装

如果项目需要固定PyYAML版本以保证兼容性,可以使用以下命令指定版本安装,这里以6.0版本为例:

pip install pyyaml==6.0

2.3 升级PyYAML

若本地已安装旧版本PyYAML,想要升级到最新稳定版本,执行升级命令:

pip install --upgrade pyyaml

安装完成后,可在Python交互环境中执行import yaml,若没有报错则说明安装成功,可正常使用。

三、PyYAML 基础使用方法

PyYAML的核心操作分为两大类:YAML文件/字符串解析(加载)Python对象转YAML(转储),分别对应yaml.load()yaml.safe_load()yaml.dump()等核心方法,其中safe_load()是官方推荐的安全解析方法,可避免执行恶意代码。

3.1 YAML字符串解析为Python对象

当我们需要将YAML格式的字符串转换为Python字典、列表等对象时,使用yaml.safe_load()方法,该方法只解析基础数据类型,不执行自定义Python对象,安全性更高。

# 导入PyYAML库
import yaml

# 定义YAML格式的字符串
yaml_str = """
name: 测试项目
version: 1.0.0
author: 开发者
features:
  - 配置解析
  - 数据序列化
  - 跨平台兼容
is_online: true
port: 8080
"""

# 将YAML字符串解析为Python字典
data = yaml.safe_load(yaml_str)

# 打印解析后的数据类型与内容
print("解析后的数据类型:", type(data))
print("解析后的数据内容:", data)
# 单独获取指定字段
print("项目名称:", data["name"])
print("项目端口:", data["port"])

代码说明

  1. 首先导入yaml库,这是使用PyYAML的前提;
  2. 定义多行YAML字符串,包含字符串、数字、列表、布尔值四种数据类型;
  3. 调用yaml.safe_load()方法完成解析,返回Python字典对象;
  4. 可通过字典键名直接获取对应的值,实现YAML数据的读取与使用。

3.2 Python对象转换为YAML字符串

将Python中的字典、列表等对象转换为标准YAML格式字符串,使用yaml.dump()方法,该方法会自动按照YAML语法格式化数据,生成可读性极高的文本内容。

import yaml

# 定义Python字典对象
python_data = {
    "app_name": "PyYAML教程",
    "language": "Python",
    "tags": ["YAML", "配置文件", "数据解析"],
    "status": "开发中",
    "config": {
        "debug": True,
        "log_path": "./logs/app.log"
    }
}

# 将Python对象转为YAML字符串
yaml_result = yaml.dump(python_data, allow_unicode=True, sort_keys=False)

# 打印生成的YAML内容
print("生成的YAML格式内容:")
print(yaml_result)

代码说明

  1. allow_unicode=True参数允许显示中文字符,避免中文乱码;
  2. sort_keys=False参数禁止自动排序字典键,保持原有数据顺序;
  3. 转换后的YAML内容自动缩进、分行,符合YAML标准语法,可读性强。

3.3 读取本地YAML文件

在实际项目中,YAML内容通常存储在.yaml.yml后缀的文件中,PyYAML可直接读取本地文件并解析,无需手动处理文件读取逻辑。

首先创建一个config.yaml文件,写入以下内容:

# 项目基础配置
database:
  host: 127.0.0.1
  port: 3306
  username: root
  password: 123456
  db_name: test_db

server:
  ip: 0.0.0.0
  port: 8000
  max_connect: 100

然后编写Python代码读取并解析该文件:

import yaml

# 打开YAML文件并读取内容
with open("config.yaml", "r", encoding="utf-8") as f:
    # 安全解析YAML文件内容
    config_data = yaml.safe_load(f)

# 输出解析后的数据库配置
print("数据库地址:", config_data["database"]["host"])
print("数据库端口:", config_data["database"]["port"])
print("服务端口:", config_data["server"]["port"])

代码说明

  1. 使用with open()语句打开文件,自动处理文件关闭操作,避免资源泄漏;
  2. 指定编码为utf-8,确保中文配置内容正常读取;
  3. 直接将文件对象传入yaml.safe_load(),即可完成文件解析,返回Python字典。

3.4 将Python对象写入YAML文件

除了读取YAML文件,PyYAML还支持将Python数据直接写入本地YAML文件,实现配置文件的生成与修改。

import yaml

# 定义需要写入的配置数据
write_data = {
    "system": {
        "os": "Windows/Linux/macOS",
        "python_version": "3.8+",
        "memory": "4GB+"
    },
    "modules": {
        "pyyaml": "6.0",
        "requests": "2.31.0",
        "pandas": "2.1.0"
    }
}

# 将数据写入YAML文件
with open("system_config.yaml", "w", encoding="utf-8") as f:
    # 写入文件,保留中文,不排序键
    yaml.dump(write_data, f, allow_unicode=True, sort_keys=False, indent=2)

print("YAML文件写入完成!")

代码说明

  1. indent=2参数设置YAML文件缩进为2个空格,让文件格式更美观;
  2. 写入完成后,会在当前目录生成system_config.yaml文件,内容符合标准YAML格式;
  3. 该方法常用于项目初始化时自动生成配置文件。

3.5 解析YAML列表与嵌套结构

YAML支持多层嵌套结构与复杂列表,PyYAML可完美解析这类复杂数据,适配企业级项目的复杂配置场景。

import yaml

# 包含嵌套字典与多层列表的YAML字符串
complex_yaml = """
project:
  name: 电商平台
  modules:
    - name: 用户模块
      functions: [登录, 注册, 修改密码]
    - name: 商品模块
      functions: [商品展示, 商品搜索, 购物车]
  version: 2.1.0
"""

# 解析复杂YAML数据
complex_data = yaml.safe_load(complex_yaml)

# 读取嵌套数据
print("项目名称:", complex_data["project"]["name"])
print("第一个模块名称:", complex_data["project"]["modules"][0]["name"])
print("用户模块功能:", complex_data["project"]["modules"][0]["functions"])

代码说明

  1. YAML支持列表嵌套字典、字典嵌套列表的复杂结构;
  2. PyYAML解析后,可通过多层键名与列表索引精准获取目标数据;
  3. 完全满足微服务、分布式项目的复杂配置读取需求。

四、PyYAML 高级使用技巧

4.1 安全解析与不安全解析的区别

PyYAML提供yaml.load()yaml.safe_load()两种解析方法,yaml.load()已被官方标记为不安全,因为它可以解析并执行自定义Python对象,若解析来自网络或不可信来源的YAML文件,可能导致代码执行漏洞。

import yaml

# 不安全的解析方式(不推荐)
# 仅用于本地可信YAML内容,禁止解析外部数据
unsafe_yaml = """
test: !!python/object/apply:subprocess.Popen
- [calc.exe]
"""
# 执行后会打开系统计算器,存在安全风险
# yaml.load(unsafe_yaml, Loader=yaml.UnsafeLoader)

# 安全解析方式(官方推荐)
# 无法执行Python对象,仅解析基础数据类型
safe_data = yaml.safe_load(unsafe_yaml)
print("安全解析结果:", safe_data)

代码说明

  1. 生产环境中必须使用yaml.safe_load(),杜绝安全漏洞;
  2. yaml.load()需要指定Loader,且仅适用于完全可信的本地数据;
  3. 安全解析会忽略自定义Python对象,保证程序运行安全。

4.2 批量解析多个YAML文档

YAML支持在一个文件中编写多个文档,使用`分隔,PyYAML可通过yaml.safe_load_all()`方法批量解析所有文档,返回可迭代对象。

创建multi_docs.yaml文件:

doc: 1
title: 第一个文档
content: 测试内容1

doc: 2
title: 第二个文档
content: 测试内容2

doc: 3
title: 第三个文档
content: 测试内容3

解析代码:

import yaml

# 读取包含多个文档的YAML文件
with open("multi_docs.yaml", "r", encoding="utf-8") as f:
    # 批量解析所有文档
    docs = yaml.safe_load_all(f)
    # 遍历所有文档内容
    for idx, doc in enumerate(docs, 1):
        print(f"第{idx}个文档:", doc)

代码说明

  1. yaml.safe_load_all()返回生成器对象,节省内存;
  2. 适用于存储多组配置、多组测试数据的场景;
  3. 遍历即可获取每个独立文档的Python对象。

4.3 自定义YAML输出格式

通过yaml.dump()的参数可自定义YAML输出格式,包括缩进、换行、浮点数精度、是否显示默认值等,满足不同项目的格式要求。

import yaml

custom_data = {
    "name": "自定义格式",
    "values": [1.23456, 2.34567, 3.45678],
    "info": {
        "author": "测试",
        "time": "2026-01-01"
    }
}

# 自定义输出格式
custom_yaml = yaml.dump(
    custom_data,
    allow_unicode=True,
    sort_keys=False,
    indent=4,
    default_flow_style=False,
    width=50
)

print(custom_yaml)

代码说明

  1. default_flow_style=False强制使用块样式输出,避免压缩格式;
  2. width=50限制每行最大宽度,提升可读性;
  3. 自定义格式后的YAML文件更符合团队开发规范。

五、PyYAML 实际项目应用案例

在实际Python项目中,PyYAML最常用于项目配置文件管理接口自动化测试数据存储爬虫配置管理机器学习参数配置等场景,下面以Web项目配置管理为例,展示完整的实战代码。

5.1 实战场景:Web项目配置管理工具

开发一个通用的配置管理工具,实现YAML配置文件的读取、修改、保存功能,支持多环境配置切换(开发环境、测试环境、生产环境)。

import yaml
import os

class YamlConfigManager:
    """YAML配置文件管理类"""
    def __init__(self, config_path="web_config.yaml"):
        self.config_path = config_path
        self.config_data = None
        # 初始化时加载配置文件
        self.load_config()

    def load_config(self):
        """加载YAML配置文件"""
        if not os.path.exists(self.config_path):
            raise FileNotFoundError(f"配置文件{self.config_path}不存在!")
        with open(self.config_path, "r", encoding="utf-8") as f:
            self.config_data = yaml.safe_load(f)
        print("配置文件加载成功!")

    def get_config(self, env="dev"):
        """获取指定环境的配置"""
        if env not in self.config_data:
            raise ValueError(f"不支持{env}环境配置!")
        return self.config_data[env]

    def update_config(self, env, key, value):
        """修改指定环境的配置"""
        if env not in self.config_data:
            self.config_data[env] = {}
        self.config_data[env][key] = value
        # 保存修改后的配置
        self.save_config()
        print(f"{env}环境{key}配置修改为{value}成功!")

    def save_config(self):
        """保存配置到YAML文件"""
        with open(self.config_path, "w", encoding="utf-8") as f:
            yaml.dump(self.config_data, f, allow_unicode=True, sort_keys=False, indent=2)

# 初始化配置文件内容(首次运行使用)
if not os.path.exists("web_config.yaml"):
    init_data = {
        "dev": {
            "host": "127.0.0.1",
            "port": 8000,
            "debug": True,
            "database": "sqlite:///dev.db"
        },
        "test": {
            "host": "192.168.1.100",
            "port": 8080,
            "debug": False,
            "database": "mysql://test:test@localhost/test_db"
        },
        "prod": {
            "host": "10.0.0.1",
            "port": 80,
            "debug": False,
            "database": "mysql://prod:prod@localhost/prod_db"
        }
    }
    with open("web_config.yaml", "w", encoding="utf-8") as f:
        yaml.dump(init_data, f, allow_unicode=True, sort_keys=False, indent=2)

# 实战调用
if __name__ == "__main__":
    # 创建配置管理器对象
    config_manager = YamlConfigManager()

    # 获取开发环境配置
    dev_config = config_manager.get_config("dev")
    print("开发环境配置:", dev_config)

    # 修改测试环境端口
    config_manager.update_config("test", "port", 8888)

    # 获取修改后的测试环境配置
    test_config = config_manager.get_config("test")
    print("修改后测试环境配置:", test_config)

代码说明

  1. 封装YamlConfigManager类,实现配置加载、读取、修改、保存的完整功能;
  2. 支持多环境配置切换,适配Web项目的不同运行环境;
  3. 自动初始化配置文件,无需手动创建,降低使用成本;
  4. 代码可直接集成到Django、Flask、FastAPI等Web框架中。

相关资源

  • Pypi地址:https://pypi.org/project/PyYAML/
  • Github地址:https://github.com/yaml/pyyaml
  • 官方文档地址:https://pyyaml.org/wiki/PyYAMLDocumentation

关注我,每天分享一个实用的Python自动化工具。