白银市网站建设_网站建设公司_CMS_seo优化
2025/12/25 15:38:37 网站建设 项目流程

Python中处理YAML文件的常用模块包括PyYAML和ruamel.yaml。

PyYAML

  • 简介:PyYAML是经典的YAML处理库,适合基本读写需求,但不支持YAML 1.2的完整特性。
  • 安装:
    bash
    复制
    pip install pyyaml
  • 核心方法:
    • yaml.safe_load(stream):安全加载YAML内容,避免执行任意代码,返回Python对象。
    • yaml.load(stream, Loader=yaml.Loader):加载YAML内容,默认不安全,需谨慎使用。
    • yaml.safe_dump(data, stream):将Python对象安全转换为YAML格式并写入流。
    • yaml.dump(data, stream):将Python对象转换为YAML格式,可能包含复杂对象的序列化。

import yaml

# 读取YAML配置文件
with open("config.yaml", "r") as f:
config = yaml.safe_load(f)
print(config["database"]["host"]) # 输出数据库主机名

# 修改配置并保存
config["database"]["port"] = 5432
with open("config_updated.yaml", "w") as f:
yaml.safe_dump(config, f, default_flow_style=False)

ruamel.yaml

  • 简介:ruamel.yaml支持YAML 1.2,保留注释和格式,适合需要高保真读写的场景。
  • 安装:
    bash
    复制
    pip install ruamel.yaml
  • 核心方法:
    • YAML().load(stream):加载YAML内容,保留注释和格式,返回CommentedMap等结构。
    • YAML().dump(data, stream):将数据写入YAML,保留原有结构(如注释)。
    • YAML().round_trip_load(stream):明确使用round-trip模式加载,保留所有细节。
    • YAML().round_trip_dump(data, stream):Round-trip模式保存数据。

from ruamel.yaml import YAML

yaml = YAML()
yaml.preserve_quotes = True # 保留引号格式

# 读取带注释的YAML
with open("commented_config.yaml") as f:
config = yaml.load(f)

# 修改配置(保留注释)
config["debug"] = True # 添加新字段
config.yaml_set_comment_before_after_key("debug", before="\n# 调试模式")

# 保存修改后的文件(保留原有注释)
with open("commented_config_updated.yaml", "w") as f:
yaml.dump(config, f)

 
特性PyYAMLruamel.yaml
YAML版本支持 1.1 1.2
保留注释/格式 ✔️
安全性 safe_load安全 默认安全
适用场景 简单读写 复杂配置、需保留格式
 

 

选择建议

  • PyYAML:适合简单场景,需注意使用safe_load/safe_dump避免安全问题。
  • ruamel.yaml:适合需要保留注释、格式或处理YAML 1.2的场景。

根据具体需求选择合适的模块,可以高效处理YAML配置文件、数据序列化等任务。

自定义类型处理(PyYAML)

import yaml

class User:
def __init__(self, name, age):
self.name = name
self.age = age

# 注册构造器和表示器
yaml.add_constructor("!User", lambda loader, node: User(**loader.construct_mapping(node)))
yaml.add_representer(User, lambda dumper, user: dumper.represent_mapping("!User", {"name": user.name, "age": user.age}))

# 序列化与反序列化
user = User("Alice", 30)
yaml_str = yaml.dump(user)
loaded_user = yaml.load(yaml_str, Loader=yaml.Loader)
 

流式处理大文件(ruamel.yaml)

from ruamel.yaml import YAML

yaml = YAML()
with open("large_file.yaml") as f:
for data in yaml.load_all(f): # 分批加载
process_data(data)
 

1. 序列化(Python对象转为YAML)

import yaml

def serialize_to_yaml():

data = {

'name': '老王',

'age': 25,

'city': '北京'

}

yaml_string = yaml.dump(data)

print(yaml_string)

# 调用函数

serialize_to_yaml()

输出:

age: 25

city: 北京

name: 老王

2. 反序列化(YAML转为Python对象)

import yaml

def deserialize_from_yaml():

yaml_string = """

age: 25

city: 北京

name: 老王

"""

data = yaml.safe_load(yaml_string)

print(data)

# 调用函数

deserialize_from_yaml()

输出:

{'name': '老王', 'age': 25, 'city': '北京'}

yaml 加强用法

1. 自定义标签和构造函数

PyYAML允许你自定义YAML标签和构造函数,以便处理Python中不存在的类型。这通常涉及到编写自定义的构造函数,并在加载时指定这些函数。

# 首先,假设你有一个名为 Person 的 Python 类,它接受名字和年龄作为参数:

class Person:

def __init__(self, name, age):

self.name = name

self.age = age

def __repr__(self):

return f"Person(name={self.name}, age={self.age})"

然后,你可以使用 PyYAML 的 add_constructor 方法来添加一个构造函数,用于处理带有自定义标签的 YAML 数据。构造函数将在解析 YAML 时被调用,并将 YAML 节点的内容传递给 Person 类的构造函数。

import yaml

from yaml.constructor import Constructor

# 自定义构造函数

def person_constructor(loader, node):

value = loader.construct_mapping(node)

name = value['name']

age = value.get('age', None)  # age 可能是可选的

return Person(name, age)

# 创建一个自定义的构造函数

class MyConstructor(Constructor):

pass

# 继承并添加自定义构造函数

MyConstructor.add_constructor('!person', person_constructor)

# 使用自定义构造函数加载 YAML

yaml_string = """

- !person

name: Alice

age: 30

- !person

name: Bob

# age is optional

"""

# 加载 YAML 数据时使用自定义构造函数

data = yaml.load(yaml_string, Loader=yaml.Loader, custom_constructor=MyConstructor)

# 输出结果

print(data)  # 输出: [Person(name=Alice, age=30), Person(name=Bob, age=None)]

在这个例子中,定义了一个名为person_constructor 的函数,它接收一个加载器(loader)和一个节点(node),并从节点中提取出 name和age来创建Person类的实例。然后,我们创建了一个自定义的构造函数类MyConstructor,并为其添加了 !person标签的构造函数。最后,使用yaml.load 方法并传入自定义构造函数类来加载 YAML 数据。

2. 转储和加载多文档

你可以使用yaml.dump_all和yaml.safe_load_all函数来一次性转储或加载多个YAML文档。

import yaml

# 多个 Python 对象

data = [

{'name': 'Alice', 'age': 30},

{'name': 'Bob', 'age': 25},

{'name': 'Charlie', 'age': 35},

]

# 使用 dump_all 将多个对象转储为多个 YAML 文档到文件中

with open('users.yaml', 'w') as outfile:

yaml.dump_all(data, outfile, default_flow_style=False)

"""

age: 30

name: Alice

---

age: 25

name: Bob

---

age: 35

name: Charlie

"""

# 使用 safe_load_all 从文件中加载多个 YAML 文档为 Python 对象列表

with open('users.yaml', 'r') as infile:

loaded_data = list(yaml.safe_load_all(infile))

# 也可以使用load_all

# loaded_data = list(yaml.load_all(infile, Loader=yaml.FullLoader))

# 输出加载后的 Python 对象列表

for item in loaded_data:

print(item)

3. 定制转储和加载

PyYAML提供了多种参数来定制转储和加载行为,比如控制缩进、行宽、是否使用块样式或流样式等。

import yaml

data = {

'name': 'John Doe',

'age': 30,

'hobbies': ['reading', 'gaming', 'traveling'],

'address': {

'street': '123 Main St',

'city': 'Anytown',

'country': 'Country'

}

}

# 定制转储行为

dumped_yaml = yaml.dump(data, default_flow_style=False, sort_keys=True, indent=4, width=60)

print(dumped_yaml)

import yaml

yaml_string = """

name: John Doe

age: 30

hobbies:

- reading

- gaming

- traveling

address:

street: 123 Main St

city: Anytown

country: Country

"""

# 使用safe_load加载YAML字符串

loaded_data = yaml.safe_load(yaml_string)

print(loaded_data)

参数说明:

•default_flow_style=False:默认情况下,PyYAML会使用块样式(block style)来转储数据,除非数据是简单的键值对或列表。设置default_flow_style=True会使PyYAML尽可能使用流样式(flow style)。

•sort_keys=True:对字典的键进行排序。这在需要可预测的输出顺序时很有用。

•indent=4:设置缩进宽度为4个空格。默认是2个空格。

•width=60:设置每行的最大宽度。当内容超过这个宽度时,PyYAML会尝试将内容换行。

4. 安全加载

始终使用yaml.safe_load和yaml.safe_load_all来安全地加载YAML数据,以防止潜在的安全风险。

5. 错误处理

PyYAML提供了详细的错误信息,帮助你定位并解决YAML解析和序列化过程中的问题。

import yaml

# 解析yaml文件

try:

with open('data.yaml', 'r') as file:

data = yaml.safe_load(file)

except yaml.YAMLError as exc:

print(exc)

# python对象序列化

data = {

'name': 'Alice',

'age': 30,

'complex_object': set([1, 2, 3])  # 集合类型不能直接序列化为YAML

}

try:

yaml_string = yaml.dump(data)

except yaml.YAMLError as exc:

print(exc)

6. 日期和时间处理

PyYAML可以处理日期和时间对象,默认将其转换为Python的datetime类型。

7. 锚点和别名

PyYAML支持YAML的锚点和别名功能,允许你在YAML文件中引用其他部分的内容。

在YAML中,锚点(&)和别名(*)是两种用于引用其他部分内容的机制。锚点用于定义一个可以引用的标识符,而别名则用于引用这个标识符。这种机制可以使得YAML文件更加简洁和易于维护,尤其是当文件中存在大量重复数据时。

• data.yaml文件

defaults: &defaults

adapter:  postgres

host:     localhost

development:

database: dev

<<: *defaults

test:

database: test

<<: *defaults

在这个例子中,我们定义了一个名为defaults的锚点,它包含了一些默认的数据库配置。然后,在development和test配置中,我们使用<<: *defaults来合并这些默认配置。这实际上是一个YAML的合并键(merge key),它允许我们将多个映射合并到一个映射中。

import yaml

# 加载YAML文件

with open('data.yaml', 'r') as file:

data = yaml.safe_load(file)

# 打印加载的数据

print(data)

8. 保留顺序

PyYAML支持保留字典的插入顺序,这对于需要保持顺序的场景非常有用。

五、注意事项

在使用PyYAML处理来自不受信任的源的YAML数据时,务必使用yaml.safe_load和yaml.safe_load_all函数,以确保不会执行潜在的恶意代码。

 

参考:https://blog.51cto.com/u_16175458/8411501

 

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询