彻底理解 YAML 及 PyYaml 操作 YAML 文件的详细指南
最编程
2024-02-14 11:52:44
...
1.yaml主要用途
YAML 是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便。
2.yaml支持的数据结构
数据结构名称 | 包含的数据类型 | 描述说明 |
---|---|---|
纯量 | 字符串、布尔值、整数、浮点数、Null、时间、日期 | 不可变数据类型,单个的、不可再分的值 |
数组 | 序列(sequence) / 列表(list) | 一组按次序排列的值 |
对象 | 映射(mapping)/ 哈希(hashes) / 字典(dictionary) | 键值对的集合 |
3.yaml语言的语法规则
- 大小写敏感
- 使用缩进表示层级关系
- 缩进时不允许使用Tab键,只允许使用空格。
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
4.yaml文件中使用不同数据类型时的规范要求
4.1 yaml文件中使用【纯量】时的规范要求
1) 数值直接以数值类型表示
示例1:price: 12.50
转为Python字典:{'price': 12.5}
2)布尔值用true和false表示。
示例1:isAdult: true
转为Python字典: {'isAdult': True}
示例2:isAdult: false
转为Python字典: {'isAdult': False}
3)null用~表示。
示例:parentId: ~
转为Python字典: {'parentId': None}
4)时间采用 ISO8601 格式。
示例:iso8601: 2019-12-14t21:59:43.10-05:00
5) 日期采用复合 iso8601 格式的年、月、日表示。
示例:datetime: 2020-12-14
6) 如果需要用到强制类型转换请使用"!!数据类型 数据取值"
示例:passwd: !!str 123456
gender: !!str true
转为Python字典: {'passwd': '123456', 'gender': 'true'}
4.2 yaml文件中使用【字符串】时的规范要求
1) 字符串默认不使用引号表示。
示例: username: lisi
转为Python字典: {'username': 'lisi'}
2) 如果字符串之中包含空格或特殊字符,需要放在引号之中。
示例: username: 'hello python'
转为Python字典: {'username': 'hello python'}
3) 单引号和双引号都可以使用,但是单引号会对特殊字符转义,而双引号不会对特殊字符转义。
示例: username: 'Hello\nPython'
nickname: "Hello\nPython"
转为Python字典: {'username': 'Hello\\nPython', 'nickname': "Hello\nPython"}
4) 单引号之中如果还有单引号,必须连续使用两个单引号转义。
示例: username: 'I''m jacky'
转为Python字典: {'username': 'I\'m jacky'}
5) 字符串可以写成多行,但从第二行开始,必须有一个单空格缩进。换行符会被自动转为空格。
示例:
title: 人生苦短
我用python
转为Python字典: {'title': '人生苦短 我用python'}
6)多行字符串可以使用|保留换行符,也可以使用>折叠换行。
示例:
books: |
天龙八部
神雕侠侣
笑傲江湖
---
date: >
yesterday
today
tomorrow
转为Python字典后:
{'books': '天龙八部\n神雕侠侣\n笑傲江湖\n'}
{'date': 'yesterday today tomorrow\n'}
7) +表示保留文字块末尾的换行,-表示删除字符串末尾的换行。
示例:
username: |+
abidal
---
username: |-
karma
转为python字典后:
{'username': 'abidal\n\n'}
{'username': 'karma'}
8) 字符串之中也可以插入HTML标签
示例:
content:
<p style="font: 14px;color: red">
这是文章正文
</p>
转为Python字典后:
{'content': '\n<p style="font: 14px;color: red">\n 这是文章正文\n</p>\n'}
4.3 yaml文件中如何进行引用操作
在yaml文件中我们通常使用“&”(锚点)和“*”(别名),来做引用操作。
&用来建立锚点(defaults),<<表示合并到当前数据,*用来引用锚点。
示例1:
username: abidal
password: 123456
hobby: ['music', 'reading', 'speak']
userInfo: &userInfo
uid: 1001
tel: 13549367372
loginUser:
<<: *userInfo
token: 1q1desfgr2344refdt54tfd00n8n7==
转为Python字典:
{'username': 'abidal', 'password': 123456, 'hobby': ['music', 'reading', 'speak'], 'userInfo': {'uid': 1001, 'tel': 13549367372}, 'loginUser': {'uid': 1001, 'tel': 13549367372, 'token': '1q1desfgr2344refdt54tfd00n8n7=='}}
示例2:
nation:
- &china Chinese
- Japan
- America
- *china
转为Python字典:
{ 'nation': ['Chinese', 'Japan', 'America', 'Chinese']}
4.4 yaml文件中使用【数组】时的规范要求
1)使用中划线"-" + 空格 + 取值
示例:
- Tom
- Jacky
- Dandy
转为python列表: ['Tom', 'Jacky', 'Dandy']
2)嵌套数组的表示方法
示例:
-
- Tom
- Jacky
- Dandy
转为python列表: [['Tom', 'Jacky', 'Dandy']]
3) 数组也可以采用行内表示法。
示例:
nation: [Chinese, Japan, America]
转为python字典: {'nation': ['Tom', 'Jacky', 'Dandy']}
4.5 yaml文件中使用【对象】时的规范要求
1)使用key + ":" + 取值
示例: name: zhangsan
转为python字典:{'name': 'zhangsan'}
2) 字典嵌套字典的表示方法
示例:
data:
user1:
username: test01
password: 123456
user2:
username: test02
password: 123456
转为python字典:
{'data': {'user1': {'username': 'test01', 'password': 123456}, 'user2': {'username': 'test02', 'password': 123456}}}
3) 字典嵌套数组的表示方法
示例:
data:
-
username: test01
password: 123456
-
username: test02
password: 123456
转为python字典:
{'data': [{'username': 'test01', 'password': 123456}, {'username': 'test02', 'password': 123456}]}
4) 将所有键值对写成一个行内对象
示例:
data: {user01:{username: test01, password: 123456}, user02:{username: test02, password: 123456}}
转为python字典:
{'data': {'user01': {'username': 'test01', 'password': 123456}, 'user02': {'username': 'test02', 'password': 123456}}}
4.6 yaml文件中使用【复合结构】时的规范要求
说白了就是将对象和数组结合起来进行使用
示例:
data:
-
username: test01
password: 123456
-
username: test02
password: 123456
testdata: {user01:{username: test01, password: 123456}, user02:{username: test02, password: 123456}}
转为python字典:
{'data': [{'username': 'test01', 'password': 123456}, {'username': 'test02', 'password': 123456}], 'testdata': {'user01': {'username': 'test01', 'password': 123456}, 'user02': {'username': 'test02', 'password': 123456}}}
5.使用PyYAML库操作yaml文件
5.1 安装PyYAML库
使用pip包管理工具命令进行安装:pip install PyYAML
5.2 检查PyYAML库是否安装成功
命令行执行:pip freeze 或者 pip list 都可以
如下图则说明安装成功。
5.3 如何使用PyYAML
这个和其他的python第三方库的使用方法大同小异, 都是需要先导包,导包成功后就可以在模块中使用该第三方模块的函数和方法。
这里我们先在命令行下看看这个库都有哪些方法:
第一步: 导入模块import yaml
第二步: 查看模块的所有属性和方法dir(yaml)
一般我们都是将yaml文件当成配置文件来进行使用,这里我们只着重文件的读写操作相关的方法说明,其实说白了yaml这和json以及pickle模块都非常相似, 操作无非就是读、写,将python类型的数据序列化之后写入到.yaml格式的文件中进行存储, 或者就是从.yaml文件读取数据反序列化成Python能识别的数据类型进行处理。文件操作的过程大多数基本都是这样。
这里我们着重说明
yaml.safe_load()、yaml.safe_load_all()、yaml.load()、yaml.load_all()、
yaml.safe_dump()、yaml.safe_dump_all()、yaml.dump()、yaml.dump_all()
5.4 读取yaml文件转成python支持的数据类型
方法名称 | 传参 | 返回值 | 解释说明 | 是否官方推荐使用 |
---|---|---|---|---|
yaml.load() | 文件句柄(文件资源对象) | python字典 | 返回值的类型取决于yaml文件的数据类型,如果是数组,返回列表对象;如果是纯量、字符串、复合类型、对象、哈希。则返回python字典对象 | 不推荐 |
yaml.load_all() | 文件句柄(文件资源对象) | python生成器对象 | 可以使用内置方法next()或者将生成器对象转成列表对象进行处理 | 不推荐 |
yaml.safe_load() | 文件句柄(文件资源对象) | python字典 | 返回值的类型取决于yaml文件的数据类型,如果是数组,返回列表对象;如果是纯量、字符串、复合类型、对象、哈希。则返回python字典对象 | 推荐 |
yaml.safe_load_all() | 文件句柄(文件资源对象) | python生成器对象 | 可以使用内置方法next()或者将生成器对象转成列表对象进行处理 | 推荐 |
方法使用示例:
- yaml.load()
- yaml.load_all()
- yaml.safe_load()
- yaml.safe_load_all()
5.5 将python数据保存到yaml文件中进行存储
方法名称 | 传参 | 返回值 | 解释说明 | 是否官方推荐使用 |
---|---|---|---|---|
yaml.dump() | python数据对象,文件资源对象 | yaml可识别的字符串 | 需要传递两个参数, 第一个是python数据类型的数据对象[列表或字典];第二个是数据要写入的文件资源对象,如果不带第二个参数,则默认会返回一个类似yaml格式的字符串 | 不推荐 |
yaml.dump_all() | python数据对象,文件资源对象 | yaml可识别的字符串 | 需要传递两个参数, 第一个是python数据类型的数据对象[列表或字典];第二个是数据要写入的文件资源对象,如果不带第二个参数,则默认会返回一个类似yaml格式的字符串 | 不推荐 |
yaml.safe_dump() | python数据对象,文件资源对象 | yaml可识别的字符串 | 需要传递两个参数, 第一个是python数据类型的数据对象[列表或字典];第二个是数据要写入的文件资源对象,如果不带第二个参数,则默认会返回一个类似yaml格式的字符串 | 推荐 |
yaml.safe_dump_all() | python数据对象,文件资源对象 | yaml可识别的字符串 | 需要传递两个参数, 第一个是python数据类型的数据对象[列表或字典];第二个是数据要写入的文件资源对象,如果不带第二个参数,则默认会返回一个类似yaml格式的字符串 | 推荐 |
方法使用示例:
-
yaml.dump([data], stream)
-
yaml.dump_all([data], stream)
-
yaml.safe_dump([data], stream)
-
yaml.safe_dump_all([data], stream)