Yaml文件介绍以及PyYAML库使用
Yaml介绍
1、介绍
YAML 是一种可读性非常高,与程序语言数据结构非常接近。同时具备丰富的表达能力和可扩展性,并且易于使用的数据标记语言。
YAML全称其实是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写,所以它强调的是数据本身,而不是以标记为重点。
2、语法特点
- 大小写敏感
- 使用缩进表示层级关系,缩进不允许使用tab键,只允许使用空格
- 缩进的空格数不重要,只要相同层级元素左对齐即可
- # 作为注释符号
3、支持的数据结构(类型)
- 对象:标示符
:,
键值对集合,又称映射(mapping)哈希(hash)字典(dict) - 数组:标示符
-,
一组按照次序排列的值,又称序列 - 纯量:单个,不可再分的值,例如:
- 字符串:字符串一般默认不加双引号,当字符串包含了空格或者特殊字符等,可需要使用双引号
- 布尔值:true、True、false、False都可以
- 整数:如1、2、3,如用逗号或者空格分割,则会变成字符串传入
- 浮点数:如2.0
- null:~ null和~都可以表示None
- 日期:如2023-03-20 格式:yyy-MM-dd
- 时间:如2023-03-20T20:20:20 格式:yyy-MM-dd HH:mm:ss,日期和时间可用T分割,也可用空格分割
PyYaml库介绍安装
PyYaml库是专门用来解析读取和写入的python库,pip安装命令如下:
pip install pyyaml
读取yaml文件
读取方法:yaml.load(yaml文件对象)
建议直接使用with来打开yaml文件对象,不需要再自己close关闭,代码如下:
import yaml with open('xxx.yaml', 'r',encoding='utf-8') as f: msg = yaml.load(f,Loader=yaml.FullLoader) print(msg)
可以看到yaml.load函数里除了传入yaml文件对象,还传了Loader参数,这个是决定yaml文件的加载方式,有以下几种:
-
BaseLoader --仅加载最基本的YAML
-
SafeLoader --安全地加载YAML语言的子集。建议用于加载不受信任的输入
-
FullLoader --加载完整的YAML语言。避免任意代码执行,PyYAML5.1版本之后默认加载调用,但会出现warning
那么新建一个yaml文件,来读取试下
对象
对象的yaml文件内容如下:
#写法一: 对象键值对使用键:值冒号分割键值,特别注意,冒号后面(右边值前面)要有一个空格。 key1: value #写法二:流式写法 key2: {k1: v1,k2: v2} #写法三:缩进标识层级 key3: name: 小明 age: 19
输出结果:
{'key1': 'value', 'key2': {'k1': 'v1', 'k2': 'v2'}, 'key3': {'name': '小明', 'age': 19}}
可以看到python解析对象打印出来也是以键值对形式的,yaml文件是用{}的字典格式,或者是左对齐层级的属性,在python里面解析出来都是字典格式
既然yaml是字典格式,python解析也是字典格式,那么如果是元组或者列表呢?
yaml文件:
#列表 key4: [1,2,3,4] #元组 key5: (5,6,7,8)
输出结果:
'key4': [1, 2, 3, 4], 'key5': '(5,6,7,8)'
yaml中的列表,在python解析后仍旧是列表格式,但元组却在python解析后变成了字符串,这是需要注意的地方
数组
数组的yaml文件内容如下:
#以-开头的行标识构成一个数组,-也需要跟一个空格,不然会被识别成字符串 name: - 小明 - 小红 - 小蓝 - {age: 19} #数组中键值对存放 student: - id: 1 age: 13 - id: 2 age: 18
需要注意:-标识符后也需要跟一个空格,不然会被识别成字符串
输出结果:
{'name': ['小明', '小红', '小蓝', {'age': 19}], 'student': [{'id': 1, 'age': 13}, {'id': 2, 'age': 18}]}
可以看到-标识后的元素,都会被当做一个列表中的元素
多维数组的yaml文件内容:
#多维数组 test: - - 1 - 2 - - 3 - 4
输出结果:
{'test': [[1, 2], [3, 4]]}
纯量
纯量的yaml文件内容如下:
字符串: admin #字符串一般默认不加双引号,当字符串包含了空格或者特殊字符等,可需要使用双引号 字符串1: 'hi world@@!! 很棒' 布尔值: True #true、True、false、False都可以 整数: 1 #如用逗号或者空格分割,则会变成字符串传入 整数分割: 1,2,3,4 浮点数: 1.2 null: ~ #null和~ 都可以表示None 日期: 2023-03-20 #格式:yyy-MM-dd 时间: 2023-03-20T20:20:20 #格式: yyy-MM-dd HH:mm:ss,日期和时间可用T分割,也可用空格分割 时间分隔: 2023-03-20 20:20:20
输出结果:
{'字符串': 'admin', '字符串1': 'hi world@@!! 很棒', '布尔值': True, '整数': 1, '整数分割': '1,2,3,4', '浮点数': 1.2, None: None, '日期': datetime.date(2023, 3, 20), '时间': datetime.datetime(2023, 3, 20, 20, 20, 20), '时间分隔': datetime.datetime(2023, 3, 20, 20, 20, 20)}
可以看到日期和时间解析出来居然是datetime里的date和datetime的方法,这样看着很别扭,但是当你用for循环去取数据时,你会发现打印出来是yaml文件里的日期和时间格式
for循环解析yaml字典的python代码:
import yaml with open('xxx.yaml', 'r',encoding='utf-8') as f: msg = yaml.load(f,Loader=yaml.FullLoader) print(msg) for k in msg: print(msg[k])
输出结果:
admin hi world@@!! 很棒 True 1 1,2,3,4 1.2 None 2023-03-20 2023-03-20 20:20:20 2023-03-20 20:20:20
可以看到通过key取出来的value值,日期和时间格式仍是yaml中一样的格式
类型强转
YAML中可以使用两个感叹号,对数据类型进行强制转换,例如:
yaml文件:
#类型强转,YAML允许使用两个感叹号。强制转换数据类型 t1: !!str 123 t2: !!float '12' t3: !!int '222'
输出结果:
{'t1': '123', 't2': 12.0, 't3': 222}
t1原本是整数int型,但被转换成了str字符串
t2原本是字符串,但被转换成了float浮点数
t3原来是字符串,但被转换成了int整数型
锚点使用
符号:&表示建立锚点,<<表示合并,*用来引用锚点
锚点就相当于一个模板,可以合并到其他数据当中,避免数据冗余
当需要合并的数据中有与锚点模板中的参数一致时,则是当前合并中数据的参数优先级更高,不会被锚点数据覆盖掉
锚点使用示例:
defaults: &defaults # 建立锚点defaults(相当于一个模板,可以合并到其他数据当中,避免数据冗余) port: 3306 ip: 127.0.0.1 user: root dev: port: 3307 <<: *defaults # 将上述的数据合并到当前锚点的地方(<<表示合并到当前数据,但与锚点中的参数一致,则是当前数据的优先级比较高,不会被锚点数据覆盖,*用来引用锚点)
输出结果:
{'defaults': {'port': 3306, 'ip': '127.0.0.1', 'user': 'root'}, 'dev': {'port': 3307, 'ip': '127.0.0.1', 'user': 'root'}}
写入数据到yaml
写入方法:yaml.dump(dict)
allow_unicode=True:解决储存时unicode编码问题
代码如下:
import yaml data = { 'school':'实验中学', 'Student': {'name':'小明','age':18}, 'Teacher': {'name':'张三','age':39} } with open('student.yaml','w',encoding='utf-8') as f: yaml.dump(data,f,allow_unicode=True)
yaml生成:
Student: age: 18 name: 小明 Teacher: age: 39 name: 张三 school: 实验中学
写入成功。但是写入的顺序是没有按照字典中的顺序写入,因为有个参数sort_keys,默认为True,表示字典中的键以A-z的顺序排序。所以要想按照实际顺序写入,将其设置为False即可
yaml.dump(data,f,allow_unicode=True,sort_keys=False)
输出结果如下:
school: 实验中学 Student: name: 小明 age: 18 Teacher: name: 张三 age: 39