白日依山尽,黄河入海流。欲穷千里目,更上一层楼。 -- 唐·王之涣

Ansible系列-基础篇-配置文件Yaml之python版

欢迎关注个人公众号 DailyOps

源站地址 配置文件Yaml之python版


@toc

什么是 yaml

yaml 可以做配置文件,但是yaml不仅仅是配置文件,其本身就是一种语言,有自己的语法和使用规范。

yaml文件后缀是有要求的,必须为yml 注意和ini文件做对比

yaml 文件介绍

1、基础规范

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

2、支持的类型

  • 对象 这里的对象是指 键值对的集合,类似python字典
  • 数组
  • 纯量 类似我们说的常量,不可在分在变的。比如 字符串、布尔值、整数、浮点数、null、时间、日期等

3、yaml对象

格式 key: value 冒号分隔,且冒号后面得有个空格

比如

1
2
3
4
5
6
7
8
9
# 基本配置
site_name: Colinspace website
site_url: http://blog.colinspace.com
# 嵌套配置
mysql_db: {host: 192.168.1.10, user: demouser}
# 嵌套配置也可以按照层级缩进配置,注意是空格缩进,而不是tab
mysql_db:
host: 192.168.1.10
user: demouser

4、yaml数组

数组是以中横线 - 开头的一组配置,且支持多维数组。比如

1
2
3
4
5
6
7
8
9
# 数组说明
# 基本数组
fruits:
- apple
- banana
- orange

# 数组行内表示
fruits: ['apple', 'banana', 'orange']

数组是有个数组名的,也就是配置的key,value是- 开头的一组数据组成的数组,该组数据对其方式保持一致。

换句话说 中横线开头的,其对齐方式一样的元素组成一个数组,重点记住这句话,因为这个是理解多维数组 的关键所在

5、多维数组

我们先看几个配置

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 多为数组, 这里是二维数组
config_multi_array:
-
- apple
- banana
- orange
-
- potato
- tomato
- cucumber

# it's array, but not tow-dimension array
# one-dimension array with two elements
config_like_multi_array:
- fruits:
- apple
- banana
- orange
- vegetables:
- potato
- tomato
- cucumber

config_like_multi_array_v2:
-
fruits:
- apple
- banana
- orange
-
vegetables:
- potato
- tomato
- cucumber

config_like_multi_array_v3:
- fruits
- apple
- banana
- orange
- vegetables
- potato
- tomato
- cucumber

config_like_multi_array_v4:
fruits:
- apple
- banana
- orange
vegetables:
- potato
- tomato
- cucumber

这里我们先给出5种key配置方式的最终的结果如下,发现只有config_multi_array 是真正的二维数组。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
"config_multi_array": [
[
"apple",
"banana",
"orange"
],
[
"potato",
"tomato",
"cucumber"
]
],
"config_like_multi_array": [
{
"fruits": [
"apple",
"banana",
"orange"
]
},
{
"vegetables": [
"potato",
"tomato",
"cucumber"
]
}
],
"config_like_multi_array_v2": [
{
"fruits": [
"apple",
"banana",
"orange"
]
},
{
"vegetables": [
"potato",
"tomato",
"cucumber"
]
}
],
"config_like_multi_array_v3": [
"fruits - apple - banana - orange",
"vegetables - potato - tomato - cucumber"
],
"config_like_multi_array_v4": {
"fruits": [
"apple",
"banana",
"orange"
],
"vegetables": [
"potato",
"tomato",
"cucumber"
]
},

从结果也证明 config_multi_array 是真正的二维数组,所以我们得知,数组一定是- 开头,

  • 如果要表示多维数组,那么第一维的- 后面不能接任何东西,比如 config_multi_array

  • 如果后面接了 key 但是 key 紧接着有冒号:的话那么就是对象,该 key 就是对象的名称;例如这里的 config_like_multi_arrayconfig_like_multi_array_v2,这两个的效果是等价的; 这种做法其实在 "数组" 中嵌套 "键值对"

    为什么? 记得上面说的 中横线开头的,其对齐方式一样的元素组成一个数组 ,所以这两个肯定是数组,而且有两个元素。 带冒号:又符合 key:value 对象的组成,所以每个元素都是对象,对象名名是key,值是个数组

  • 如果后面接了 key 但是 key 紧接着没有冒号:的话,他就会和后面的数组元素一起组成一个数组,比如这里的 config_like_multi_array_v3,其实这种配置方式是”错误”的

  • 另外比如第五种配置config_like_multi_array_v4方式,没有-开头,所以就是个对象,每个对象的值是个数组,这种方式其实是种复合结构,或者叫 在 "键值对" 中嵌套 "数组"

6、复合结构

符合结构其实就是 对象和数组的结合使用了,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
# 复合结构,即 对应和数组组合
# 复合结构,即 对应和数组组合
composite_structure:
name: compound_demo
classes:
-
class_one: 1
name: 三年一班
students: 32
-
class_two: 2
name: 三年二班
students: 35

这里 composite_structure 对象 中有对象结构nameclasses,而对象classes 的值是个数组,有两个元素,每个元素是个对象,又由三个对象构成

python操作yaml文件

一个yaml文件中可以存在多个部分,每个部分开头 ---

  • python读取解析yaml文件

    yaml.load(f_handler, Loader=yaml.Loader) 解析单部分文件
    yaml.load_all(f_handler, Loader=yaml.FullLoader) 解析多部份文件

  • python 写入配置到 yaml 文件

    yaml.dump(python_dict_obj, f_handler)

  • 其他方法

    loader.items() 列出所有配置项(key和value)
    loader.keys() 列出所有配置项的key
    loader.values() 列出所有配置项的value
    loader.get(key) 获取某个配置项key对应的值

python 操作 yaml 脚本#!/usr/bin/env python

encoding: utf-8

Author: colinspace.com

Desc: python yaml demo

import sys
import yaml
import json

yml_file = “demo.yml”
yml_file_multi = “multi.yml”

print(“\n==> 转化yaml内容为字典或者列表 - 单部分”)
with open(yml_file, ‘r’, encoding=’utf-8’) as f:
try:
loader = yaml.load(f, Loader=yaml.Loader)
# type is dict with single quotes; can’t use python -m json.tool to format result
# print(type(loader))
# print(loader)

# type is str with double quotes
# print(type(json.dumps(loader)))
print(json.dumps(loader))

except Exception as e:
print(e)

print(“\n==> 转化yaml内容为字典或者列表 - 多部分”)
with open(yml_file_multi, ‘r’, encoding=’utf-8’) as f:
try:
# loader here is generator
loader = yaml.load_all(f, Loader=yaml.FullLoader)
for item in loader:
print(json.dumps(item))

except Exception as e:
print(e)

print(“\n==> 尝试写入配置到yaml文件”)
py_dict = {
“cache”: {
“host”: “192.168.1.11”,
“port”: 3306
},
“languages”: [“python”, “golang”, “Java”]
}

with open(“demo_write.yml”, “w”, encoding=”utf-8”) as f:
yaml.dump(py_dict, f)

print(“==> 写入之后的结果”)
with open(“demo_write.yml”, “w”, encoding=”utf-8”) as f:
print(f.read())

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/env python
# encoding: utf-8
# Author: colinspace.com
# Desc: python yaml demo
#

import sys
import yaml
import json

yml_file = "demo.yml"
yml_file_multi = "multi.yml"


print("\n==> 转化yaml内容为字典或者列表 - 单部分")
with open(yml_file, 'r', encoding='utf-8') as f:
try:
loader = yaml.load(f, Loader=yaml.Loader)
# type is dict with single quotes; can't use python -m json.tool to format result
# print(type(loader))
# print(loader)

# type is str with double quotes
# print(type(json.dumps(loader)))
print(json.dumps(loader))
except Exception as e:
print(e)

print("\n==> 转化yaml内容为字典或者列表 - 多部分")
with open(yml_file_multi, 'r', encoding='utf-8') as f:
try:
# loader here is generator
loader = yaml.load_all(f, Loader=yaml.FullLoader)
for item in loader:
print(json.dumps(item))

except Exception as e:
print(e)


print("\n==> 尝试写入配置到yaml文件")
py_dict = {
"cache": {
"host": "192.168.1.11",
"port": 3306
},
"languages": ["python", "golang", "Java"]
}

with open("demo_write.yml", "w", encoding="utf-8") as f:
yaml.dump(py_dict, f)

print("==> 写入之后的结果")
with open("demo_write.yml", "w", encoding="utf-8") as f:
print(f.read())

结果如下

1
2



扩展

1、windows下no module named pip 报错

在windows的 cmd 命令行中输入如下命令进行修正

1
python -m ensurepip

如果想要升级 pip 需要执行如下命令

1
2
3
# 不能直接使用 pip install -U pip 
# -U 等效于 --upgrade
python -m pip install -U pip

2、python json.tool 中文乱码

显示乱码的原因是,json为了安全会把内容都转义为ascii编码,我们可以通过参数ensure_ascii 不让json强行将内容都转义为ascii编码,中文原样输出即可。

python2 和 python3 的方式有所不同

python2 需要修改源码的配置,在系统安装路径下找到 json/tools.py 文件,添加参数配置ensure_ascii=False,比如

1
2
3
json.dump(obj, outfile, sort_keys=True, indent=4, separators=(',', ': '))
修改为
json.dump(obj, outfile, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)

python3 添加参数 --no-ensure-ascii 即可 ,我们从其输出用法可以得到

1
2
3
usage: python -m json.tool [-h] [--sort-keys] [--no-ensure-ascii] [--json-lines]
[--indent INDENT | --tab | --no-indent | --compact]
[infile] [outfile]

所以使用如下命令

1
python demo_yaml.py | python -m json.tool --no-ensure-ascii
作者

Colin

发布于

2021-12-12

许可协议