添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
2020年12月18日 07:59:52
评论 3487字 阅读11分37秒
摘要 这一篇介绍 Python 中使用 yaml 的方式加载配置文件,包含关于 pyyaml 的简单使用,读入和写入配置文件。

之前我们介绍过使用 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:
  • 读取 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?