Python读写yaml文件

YAML 是一种常见的标记性语言,常用于配置文件。本文就使用Python 对yaml文件的读写展开讨论。

yaml 语法请查看:https://blog.csdn.net/yuelai_217/article/details/130582142

一、读取yaml文件

1.1、读取单组数据

Python 读取yaml常见的有两种方式,一种是使用pyyaml,另一种是ruamel.yaml

1.1.1、pyyaml

pip install pyyaml

test.yaml如下:

name: zhangsan
age: 45

读取文件如下:

# coding=utf-8

import yaml


def read_yaml(file_path):
    with open(file_path, "r") as f:
        return yaml.safe_load(f)


data = read_yaml("test.yaml")
print(data)  # {'age': 45, 'name': 'zhangsan'}

1.1.2、ruamel.yaml

pip install ruamel.yaml

同样解析test.yaml,如下:

from ruamel import yaml


with open("test.yaml") as f:
    config = yaml.load(f, Loader=yaml.RoundTripLoader)

print config  # ordereddict([('name', 'zhangsan'), ('age', 45)])
print config["name"]

1.2、读取多组数据

修改test.yaml如下

name: zhangsan
age: 45
---
name: lisi
age: 25
---
name: wangwu
age: 33
# coding=utf-8

import yaml

def read_yaml(file_path):
    with open(file_path, "r") as f:
        return yaml.safe_load_all(f.read())


data = read_yaml("test.yaml")
print(data)  

for d in data:
    print d

# 结果如下
<generator object load_all at 0x102d0c9b0>
{'age': 45, 'name': 'zhangsan'}
{'age': 25, 'name': 'lisi'}
{'age': 33, 'name': 'wangwu'}

获取列表式结果

# coding=utf-8

import yaml

def read_yaml(file_path):
    with open(file_path, "r") as f:
        return list(yaml.safe_load_all(f.read()))


data = read_yaml("test.yaml")
print(data)  

# 结果如下
[{'age': 45, 'name': 'zhangsan'}, {'age': 25, 'name': 'lisi'}, {'age': 33, 'name': 'wangwu'}]

使用ruamel.yamlPyYAML在处理多组数据时结果一致

二、写入数据

2.1、写入单组数据

使用 safe_dump写入单组数据

# coding=utf-8

import yaml
import os


def write_date_to_yaml(date):
    file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'test.yaml'))
    with open(file_path, 'w') as f:
        yaml.safe_dump(date, f, allow_unicode=True)


info = {"name": "小红", "age": 18}
write_date_to_yaml(info)


# test.yaml 如下
age: 18
name: 小红

# 文件被重写,原有内容丢失,修改'w'为'a',报错,因为没有插入多组数据分隔符
name: zhangsan
age: 45
---
name: lisi
age: 25
---
name: wangwu
age: 33
age: 18  # 缺少分隔符 ---
name: 小红

2.2、追加多组数据

使用 safe_dump_all写入多组数据

import yaml
# from ruamel import yaml
import os

info = {"name": "小红", "age": 18}
info1 = {"name": "小蓝", "age": 19}


def write_date_to_yaml():
    file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'test.yaml'))
    with open(file_path, 'a') as f:
        yaml.safe_dump_all([info1, info], f, allow_unicode=True, default_flow_style=False)


write_date_to_yaml()

# 结果如下:
age: 45
name: zhangsan
---
age: 25
name: lisi
---
age: 33
name: wangwu
                 # 此处没有分隔符,导致错误
age: 19
name: 小蓝
---
age: 18
name: 小红

手动添加---结果如下:

import yaml
# from ruamel import yaml
import os

info = {"name": "小红", "age": 18}
info1 = {"name": "小蓝", "age": 19}


def write_date_to_yaml():
    file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'test.yaml'))
    with open(file_path, 'a') as f:
        yaml.safe_dump_all(['---', info1, info], f, allow_unicode=True, default_flow_style=False)


write_date_to_yaml()

# 结果如下:
age: 45
name: zhangsan
---
age: 25
name: lisi
---
age: 33
name: wangwu

'---'   # 多出此行,是错误的
---
age: 19
name: 小蓝
---
age: 18
name: 小红

最终解决办法如下,采用先读取数据,修改数据后统一写入的办法,此处将读取的数据以列表形式展示,如果是单组数据,直接使用字典的update()方法更新。

# coding=utf-8
import yaml
import os

info = {"name": "小红", "age": 18}
info1 = {"name": "小蓝", "age": 19}


def update_yaml():
    file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'test.yaml'))
    with open(file_path, 'r') as f:
        data = list(yaml.safe_load_all(f))
        data.append(info)
        data.append(info1)

        # data.update(info)
        with open(file_path, 'w') as fl:
            yaml.safe_dump_all(data, fl, encoding='utf-8')


# sign = "---"
update_yaml()

# 结果如下
age: 45
name: zhangsan
---
age: 25
name: lisi
---
age: 33
name: wangwu
---
age: 18
name: "\u5C0F\u7EA2"
---
age: 19
name: "\u5C0F\u84DD"

汉字没有正常显示,需要使用中文unicode码写入allow_unicode=True,修改为:

yaml.safe_dump_all(data, fl, allow_unicode=True)

# 结果如下
age: 45
name: zhangsan
---
age: 25
name: lisi
---
age: 33
name: wangwu
---
age: 18
name: 小红
---
age: 19
name: 小蓝

附:ruamel.yamlPyYAML区别

ruamel.yamlPyYAML都是用于处理YAML格式的Python库,但它们之间有一些区别:

  • 安装方式:ruamel.yaml可以通过pip直接安装,而PyYAML需要在安装前先安装C编译器。

  • YAML标准支持性:ruamel.yaml支持最新的YAML 1.2标准,而PyYAML只支持旧的YAML 1.1。

  • 兼容性:ruamel.yaml与PyYAML的兼容性较低,因为它们使用不同的解析器和加载器,所以在某些情况下,ruamel.yaml不能正确地解析PyYAML生成的YAML文件。

  • 性能:ruamel.yaml的解析速度要比PyYAML快,特别是在处理大型YAML文件时。

  • 功能:ruamel.yaml提供了更多的功能,如可以保留注释、顺序等YAML文件的元数据信息,支持更多的Python数据类型和格式。

总的来说,如果需要处理较新的YAML标准或需要更高的性能和更多的功能,可以选择ruamel.yaml。如果只是简单地需求解析YAML文件,PyYAML是一个更简单的选择。

附:yaml.safe_load()yaml.load()区别

在PyYAML库中,yaml.safe_load()和yaml.load()都可以用来解析YAML文件,但是有一些区别:

  • 安全性: yaml.safe_load()可以安全地从YAML文档中加载数据,而不会执行任何可疑的Python代码。这使得它非常适合处理来自不受信任的源的YAML文档。yaml.load()则不提供此安全功能,因此不建议使用它来加载未知或不受信任的YAML文档。

  • 数据类型:yaml.safe_load()只能加载基本的Python数据类型,例如字符串、数字、列表和字典等。而yaml.load()可以加载任何Python对象,包括自定义类实例和Python内置类型的子类。

  • 执行Python代码:yaml.load()可以执行YAML文档中嵌入的Python代码。这使得它可以用于一些高级用例,例如将Python代码编译为YAML文档,并在不同的Python环境中加载它们。但是,由于安全风险,不建议在加载未知或不受信任的YAML文档时使用此功能。

因此,在处理未知或不受信任的YAML文档时,推荐使用yaml.safe_load()来保证安全性。

参考文档:

1、https://www.cnblogs.com/yxfeng/p/10396288.html

2、https://www.cnblogs.com/hhaostudy/p/16104098.html

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2023年8月4日
下一篇 2023年8月4日

相关推荐