Yaml文件介绍以及PyYAML库使用

发布时间 2023-03-31 10:42:58作者: 测试-13

Yaml介绍

1、介绍

YAML 是一种可读性非常高,与程序语言数据结构非常接近。同时具备丰富的表达能力和可扩展性,并且易于使用的数据标记语言。
YAML全称其实是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写,所以它强调的是数据本身,而不是以标记为重点。

2、语法特点

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

3、支持的数据结构(类型)

  • 对象:标示符:,键值对集合,又称映射(mapping)哈希(hash)字典(dict)
  • 数组:标示符-,一组按照次序排列的值,又称序列
  • 纯量:单个,不可再分的值,例如:
  1. 字符串:字符串一般默认不加双引号,当字符串包含了空格或者特殊字符等,可需要使用双引号
  2. 布尔值:true、True、false、False都可以
  3. 整数:如1、2、3,如用逗号或者空格分割,则会变成字符串传入
  4. 浮点数:如2.0
  5. null:~   null和~都可以表示None
  6. 日期:如2023-03-20 格式:yyy-MM-dd
  7. 时间:如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