背景

程序中难以避免需要写配置文件来控制参数,本人之前在 Python 中使用参数的方法包括两种:

  • 将参数写在 Python 文件 config.py 中,这样好处是可以直接导入这个 config.py 中的参数,但是通用性不太好;
  • 命令行输入参数,使用 argsparse 或者 click 等模块,但是在大型项目中一般不会在命令行手动输入参数;

因此,需要一个统一的撰写配置文件规范而且配置文件较为通用且易读,有没有解决方案呢?答案是有的,目前介绍一种配置文件规范 YAML 语言

YAML 简介

YAML 是专门用来写配置文件的语言,官方全称为“YAML Ain’t Markup Language”,实质上是一种通用的数据串行化格式,非常简洁和强大,很多软件都使用 YAML 作为配置文件,例如 Github Actions、K8s 等。

可以将 YAML 内容保存在具有任何扩展名的文件中:.yml.yaml 或其他任何扩展名。建议优先使用.yaml而不是.yml,但是由于历史原因许多Windows程序员不使用具有三个以上字符的扩展名,因此选择使用.yml

基本语法规则如下:

  • 大小写敏感;
  • 使用缩进表示层级关系;
  • 缩进时不允许使用Tab键,只允许使用空格;
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可;

# 表示注释,该行内容会被解析器所忽略。

数据结构

支持的数据结构包括三种:

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

对象和数组的语法容易理解,简单给出一种复合结构的示例说明

1
2
3
4
5
6
7
8
9
# 对象 + 数组测试
object:
- list1
- list2
- list3
object:
sub_object1: value1
sub_object2: value2
sub_object3: value3

📢 注意:对象和数组可以多层嵌套,每个嵌套的元素都可以不同,例如同一个数组的元素可以使用不同的结构。

标量需要注意下格式,例如字符串、日期、数字、空等等。

1
2
3
4
5
6
# 标量测试
none: ~
time: 2021-4-26 12:12:12
str1: shenmengjia
str2: !!str 123456
boolean: true

!!str 表示强制类型转换,否则数字字符串将被默认读为整数。

引用

& 用来建立锚点(defaults),<<表示合并到当前数据,*用来引用锚点。

用法示例

1
2
3
4
5
6
7
8
9
10
11
defaults: &defaults
adapter: postgres
host: localhost

development:
database: myapp_development
<<: *defaults

test:
database: myapp_test
<<: *defaults

PyYAML 教程

由于在个人在 Python 文件中使用配置文件较多,因此再介绍下在 Python 文件中读取 YAML 配置文件过程。

安装

1
pip install pyyaml

例如一份 YAML 配置文件 config.yaml 如下所示

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
# 对象 + 数组测试
object1:
- list1:
key1: value1
- list2
- list3
object2:
sub_object1: value1
sub_object2: value2
sub_object3: value3

# 标量测试
none: ~
time: 2021-4-26 12:12:12
str1: shenmengjia
str2: !!str 123456
boolean: true

# 锚点测试
defaults: &defaults
adapter: postgres
host: localhost

development:
database: myapp_development
<<: *defaults

test:
database: myapp_test
<<: *defaults

读取配置文件:

1
2
3
import yaml
with open("./config/config.yaml", 'r') as stream:
config = yaml.safe_load(stream)

对应的配置结果如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
In [1]: config                                                                                                                                                      
Out[1]:
{'object1': [{'list1': {'key1': 'value1'}}, 'list2', 'list3'],
'object2': {'sub_object1': 'value1',
'sub_object2': 'value2',
'sub_object3': 'value3'},
'none': None,
'time': datetime.datetime(2021, 4, 26, 12, 12, 12),
'str1': 'shenmengjia',
'str2': '123456',
'boolean': True,
'defaults': {'adapter': 'postgres', 'host': 'localhost'},
'development': {'adapter': 'postgres',
'host': 'localhost',
'database': 'myapp_development'},
'test': {'adapter': 'postgres',
'host': 'localhost',
'database': 'myapp_test'}}

其它用法参考详细文档参考:https://pyyaml.org/wiki/PyYAMLDocumentation

Contact