Hydra: Python中的多配置环境管理
Hydra
Hydra是一个开源的Python配置管理框架,使用它可以简化多环境应用的开发。简单来说,我们可以将不同环境的配置写在不同的yaml配置文件中,使用Hydra可以帮助我们方便地加载和组合不同的配置,同时还支持使用命令行进行动态配置覆盖。Hydra的官方文档地址为:Getting started | Hydra,可以通过pip进行安装:
1 |
|
所谓配置管理,实际上就可以理解为如何将对应的配置(key-value对)以dict的形式加载到我们的程序中,让程序能够动态访问。我们接下来也就会重点关注hydra如何能够做到这一点。
Quick Start
在hydra中,配置通过yaml配置文件来进行管理。例如我们可以使用数据库操作的场景。通常,我们会将配置文件放在单独的conf目录下,同时在配置文件中提供对应的信息,例如:
1 |
|
此时,我们可以通过python代码hydra-test.py
进行配置的访问,只需要调用hydra提供的注解,并且指定配置存放的目录以及配置的名称即可:
1 |
|
这里python文件与conf在同级目录下。如果直接直接运行,可以得到如下输出,可以看到配置以多层嵌套dict的方式被读入程序中。
1 |
|
上面的hydra注解会给main函数传入一个DictConfig的cfg,我们可以将其理解为一个嵌套的多层字典。我们可以通过
cfg.db.driver
的attribute style方式调用,也可以通过cfg['db']['driver']
的dictionary style方式调用。并且从配置文件到DictConfig到过程中存在类型推断。
同时,我们还可以在运行程序时进行配置的覆盖。例如下面的运行命令,会使用命令行中指定的配置value覆盖文件中的值:
1 |
|
在使用命令行的时候,需要注意符号的使用。如果是在配置文件中已经存在的配置,那么就直接在命令行中指定;如果是在配置文件中不存在的配置,那么需要使用+
进行修饰;同时hydra还提供++
,该符号能够同时兼容以上两种情况。
1 |
|
1 |
|
多配置文件组合
配置组
hydra提供配置组的概念,允许我们同时存放多个同层级的配置。在配置目录conf下,每个子目录代表一个配置组,配置组中是对应不同的配置,每个配置组中只能同时加载一个配置。例如下面的层次结构(hydra-test.py
仍然是Quick
Start中的程序,用于获取当前配置并输出):
1 |
|
配置文件的内容分别如下:
1 |
|
1 |
|
1 |
|
在config.yaml中,通过defaults来指定db配置组默认使用哪一个配置。defaults
是hydra中的一个特殊保留指令,用来指定配置组的默认使用配置。
直接通过命令行运行,运行的就是db配置组中mysql的配置:
1 |
|
同样我们可以在命令行指定db配置组使用postgresql。当然此时也同样支持使用命令行覆盖对应参数:
1 |
|
当然在原始入口conf/config.yaml
配置文件中,我们也可以指定配置组中的属性。此时为了能够加载该属性,我们需要在defaults
中增加_self_
关键字,表示默认加载自身。此时需要注意覆盖关系,实际执行类似于按照顺序加载,在后面加载的属性会覆盖前面加载的属性。例如此时conf/config.yaml
内容如下:
1 |
|
输出如下,此时后面的mysql配置就覆盖了config中的config_user。如果把_self_
移动到后面,则会加载出config_user
1 |
|
Packages
在Hydra配置组中,存在Package的概念。在默认情况下,Package即为该配置的目录结构,类似于Java中的Package。例如,config/db/mysql.yaml
这个配置文件所属的Package就是config.db
。Package最终体现在得到的配置字典中,这也就意味着对于该配置文件来说,最终在程序中得到的配置dict中,它的前置层次就是config.db
,而mysql.yaml
中的键值对就在这个前置层次之下进行组织。Package可以通过使用defaults或者Packages指令来修改。
首先构造下面的场景,配置文件的组织形式如下:
1 |
|
每个配置文件内容如下:
1 |
|
1 |
|
1 |
|
1 |
|
此时如果我们正常运行程序,可以得到如下的字典结构,可以看到都是按照正常的层级结构进行组织的。
1 |
|
第一种改变Package的方式是通过在defaults列表中进行操作。使用@PACKAGE
操作符,改变的是defaults列表引入的yaml所对应的pacakge。
例如下面:
1 |
|
1 |
|
输出的层级结构如下,可以看到在key结构中,原本的server变成了admin,db变成了backup
1 |
|
第二种改变pacakge的方式是在对应yaml文件的首行直接使用package指令,它直接指定该yaml对应的pacakge。
例如修改mysql.yaml
内容如下,这
1 |
|
得到的配置字典层级结构如下。
1 |
|
在这种方式下,有一种常用的保存字是_global_
,它表示直接将该yaml的层级提升到最顶级。
可以看到一共有三种方式影响package,它们的优先关系如下:
- 在defaults列表中指定的package
- 在yaml文件中指定的package
- 默认文件层级结构