文章目录(Table of Contents)
简介
之前我们介绍过使用 configparser 来读取配置文件(Python读入配置文件-configparser介绍),这里我们介绍另外一种 Python 写配置文件的方式,使用 yaml 来写配置文件。我们会使用 pyyaml 库来完成。
这一篇的主要内容参考自,Python使用PyYAML库读写yaml配置文件,同时也结合了一些 pyyaml 官方文档中的内容,PyYAML Documentation。
Yaml 配置文件介绍
为了可以读取 yaml 文件,我们需要安装 pyyaml 并导入 yaml 模块。使用 pip install pyyaml
来进行安装即可。
yaml 文件规则
首先来说明一下 yaml 配置文件书写的时候的规则:
- 配置文件区分大小写;
- 使用缩进表示层级关系;
- 使用空格键缩进,缩进的空格数目不固定,只需要相同层级的元素左侧对齐;
- 文件中的字符串不需要使用引号标注,但若字符串包含有特殊字符则需用引号标注;
- 注释标识为 #
- 键值对用冒号 ':' 结构表示,冒号与值之间需用空格分隔
- 可以在配置前加有 "-" 符号,符号与值之间需用空格分隔,来表示数组。(也可以直接写成 list 的形式即可)
yaml 配置文件支持的数据类型如下所示:
- # 纯量
- s_val: name # 字符串:{'s_val': 'name'}
- spec_s_val: "name\n" # 特殊字符串:{'spec_s_val': 'name\n'
- num_val: 31.14 # 数字:{'num_val': 31.14}
- bol_val: true # 布尔值:{'bol_val': True}
- nul_val: null # null值:{'nul_val': None}
- nul_val1: ~ # null值:{'nul_val1': None}
- time_val: 2018-03-01t11:33:22.55-06:00 # 时间值(iso8601格式):{'time_val': datetime.datetime(2018, 3, 1, 17, 33, 22, 550000)}
- date_val: 2019-01-10 # 日期值:{'date_val': datetime.date(2019, 1, 10)}
下面是一个基本的 yaml 配置文件的示例,包含了一些基本的元素:
- train:
- batch_size: 25
- lr: 0.001
- train_index: [1,2,3]
- test:
- batch_size: '100'
- test_index:
- - 1
- - 2
- - 3
读取 yaml 配置文件
我们使用 yaml.safe_load
来读取上面的配置文件。读取的结果会保存为 python 中的 dict 类型。
- import os
- import yaml
- with open(os.path.join('test.yaml')) as f:
- cfg = yaml.safe_load(f) # 读取配置文件
- print(cfg)
最终输出的值如下所示:
这一部分可以和 easydict 配合使用,关于 easydict 的内容可以查看链接,Python 中 EasyDict 的使用。
- import os
- import yaml
- from easydict import EasyDict
- def setup_config():
- with open(os.path.join('test_config.yaml')) as f:
- cfg = yaml.safe_load(f) # 读取配置文件
- cfg = EasyDict(cfg) # 存成 Easydict 的格式
- return cfg
生成 yaml 配置文件的格式(保存为 .yaml 文件)
我们可以使用 yaml.dump
来将字典或是列表转换为 yaml 的标准格式。还是上面的例子,这里我们使用 yaml.dump 来看一下最终生成的结果。
- import os
- import yaml
- with open(os.path.join('test.yaml')) as f:
- cfg = yaml.safe_load(f) # 读取配置文件
- print(cfg)
- print('='*10)
- print(yaml.dump(cfg))
可以看到使用 yaml.dump 可以生成 yaml 所需要的格式。
我们也可以将输出的内容直接保存到文件中。(yaml.dump
accepts the second optional argument, which must be an open text or binary file. In this case, yaml.dump
will write the produced YAML document into the file. Otherwise, yaml.dump
returns the produced document.)
- import os
- import yaml
- with open(os.path.join('test.yaml')) as f:
- cfg = yaml.safe_load(f) # 读取配置文件
- stream = open('document.yaml', 'w', encoding='utf8')
- yaml.dump(cfg, stream)
这样可以直接将 yaml 保存到文件 document.yaml 中去。
自定义 .yaml 的输出结果
上面使用 yaml.dump
输出结果就是默认的效果。我们看一个例子:
- import yaml
- tmp_dict = {'train': {'batch_size': 256, 'learning_rate':0.001}}
- with open('1.yaml', 'w', encoding='utf8') as stream:
- yaml.dump(tmp_dict, stream)
这个时候文件中保存的效果如下所示:
现在我们想要把所有的 key
都加上引号,也就是变为如下的效果:
- "train":
- "batch_size": 256
- "learning_rate": 0.001
我们可以使用 yaml.add_representer
的方式,下面是对每一个字符串都进行单独的处理:
- def quoted_presenter(dumper, data):
- return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
- yaml.add_representer(str, quoted_presenter)
这个时候在将上面的 tmp_dict 保存到文件,所有的 key 就都会被加上引号,如下所示:
如果现在我们希望 train
没有引号,batch_size
和 learning_rate
有引号。这个时候我们可以对原始的 dict
进行简单的处理。我们可以将所有的 train
加上 \n
,然后再 quoted_presenter
中删除,并对没有 \n
的字符加上引号,完整代码如下所示:
- _tmp_dict = {}
- for _key in tmp_dict:
- _tmp_dict[_key+'\n'] = tmp_dict[_key]
- def quoted_presenter(dumper, data):
- if '\n' in data:
- print(data, '1')
- data = data.replace('\n', '')
- return dumper.represent_scalar('tag:yaml.org,2002:str', data) # 原样返回
- else:
- print(data)
- return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
- yaml.add_representer(str, quoted_presenter)
最终的效果如下所示,可以看到 train
上没有引号,但是batch_size
和 learning_rate
有引号。
参考资料,How can I control what scalar form PyYAML uses for my data?
- 微信公众号
- 关注微信公众号
- QQ群
- 我们的QQ群号
评论