PyYAML - 在Python中使用YAML

YAML是一种强大的具有可读性的数据序列化标准。在Python中,可以使用PyYAML对YAML格式的文件进行处理,比如:读写配置文件。

PyYAML - 在Python中使用YAML

0 链接

YAML

YAML: YAML Ain't Markup Language

What It Is: YAML is a human friendly data serialization standard for all programming languages.

  • YAML标准官方网站

PyYAML

PyYAML is a full-featured YAML framework for the Python programming language.

  • PyYAML,Python的全功能YAML框架

PyYAML Documentation

PyYAML is a YAML parser and emitter for Python.

  • PyYAML文档

YAML 入门教程 - runoob.com

  • 中文、易上手的YAML入门教程

1 YAML

1.1 概述

YAML是一种数据序列化标准,目前看来是最强大的可读型数据序列化标准。

与传统配置文件格式INI(*.ini)或是JSON(*.json)相比,YAML(*.yml)是不仅支持的数据类型丰富,而且还支持注释之类的增强可读性的功能。

INI JSON YAML
数据类型 无*
层次结构 一层 多层 多层
支持注释 支持 不支持 支持
  • INI本身不体现数据类型,需读取时指定数据类型,否则均视为字符串。

1.2 语法规则

1.2.1 基本语法

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • #表示注释

1.2.2 数据类型

YAML 支持以下几种数据类型:

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值

1.3 示例

在官方文档就有示例,不过我更推荐YAML 入门教程 - runoob.com的一个例子,上手快。

我做了一定修改和测试(增加了dict):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# YAML支持注释
boolean:
- TRUE #true,True都可以
- FALSE #false,False都可以
float:
- 3.14
- 6.8523015e+5 #可以使用科学计数法
int:
- 123
- 0b1010_0111_0100_1010_1110 #二进制表示
null:
nodeName: 'node'
parent: ~ #使用~表示null
string:
- 哈哈
- 'Hello world' #可以使用双引号或者单引号包裹特殊字符
- newline
newline2 #字符串可以拆成多行,每一行会被转化成一个空格
dict:
hp: 13
sp: 5
date:
- 2018-02-17 #日期必须使用ISO 8601格式,即yyyy-MM-dd
datetime:
- 2018-02-17T15:02:31+08:00 #时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区
  • 经过我的测试,Python的tuple类型是不认的,只是解析为字符串,不过可以用list。

2 PyYAML

详细的请参考官方文档PyYAML Documentation,以下介绍最简单的操作。

2.1 安装

1
conda install pyyaml

或使用pip:

1
pip install pyyaml

2.2 使用

2.2.1 safe_load

把上述1.3的示例存入config.yml中,通过以下代码读取:

1
2
3
4
5
import yaml

with open('config.yml', 'r', encoding='utf-8') as f:
cfgs = yaml.safe_load(f)
print(cfgs)
  • 一般建议使用safe_load,限制使用安全的、核心的YAML功能,否则YAML可以解析各种你想不到的东西,可能会调用Python中的任何东西,例如:直接构建一个类对象。(具体见PyYAML Documentation文档中的解释)

  • 非安全函数为yaml.load(...)

结果是一个`dict

1
{'boolean': [True, False], 'float': [3.14, 685230.15], 'int': [123, 685230], None: {'nodeName': 'node', 'parent': None}, 'string': ['哈哈', 'Hello world', 'newline newline2'], 'dict': {'hp': 13, 'sp': 5}, 'date': [datetime.date(2018, 2, 17)], 'datetime': [datetime.datetime(2018, 2, 17, 15, 2, 31, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800)))]}

或通过IPython读取:

1
2
3
4
5
6
7
8
9
10
11
12
IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: cfgs
Out[1]:
{'boolean': [True, False],
'float': [3.14, 685230.15],
'int': [123, 685230],
None: {'nodeName': 'node', 'parent': None},
'string': ['哈哈', 'Hello world', 'newline newline2'],
'dict': {'hp': 13, 'sp': 5},
'date': [datetime.date(2018, 2, 17)],
'datetime': [datetime.datetime(2018, 2, 17, 15, 2, 31, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800)))]}

2.2.2 safe_dump

对于Python对象,也可以导出到文件流中:

1
2
3
4
5
import yaml

with open('config.dump.yml', 'w', encoding='utf-8') as f:
cfgs = {'name': 'tom', 'age': 20, 'attrs': [i for i in range(5)]}
yaml.safe_dump(cfgs, f)
  • 非安全函数为yaml.dump(...)

结果在config.dump.yml中:

1
2
3
4
5
6
7
8
age: 20
attrs:
- 0
- 1
- 2
- 3
- 4
name: tom

如果未指定输出流,直接导出:

1
yaml.safe_dump(cfgs)

结果会直接显示出来,相当于默认为标准IO。

stream=None时,源码中根据有无指定encoding来决定streamio.StringIO()或是io.BytesIO()

3 小结

不难看出,YAML格式的文件非常适合作为配置文件:

  1. 可读性强;
  2. 自带数据格式:而INI不支持,需要读取时设定读取方法;
  3. 支持层次结构:而INI不支持;
  4. 语法简单:基本就是冒号和空格(JSON还需要用大括号包好);
  5. 和Python兼容很好:一个配置文件读出来就是Python的一个dict。