🍕 Easy Configuration(ezkfg)

GitHub: 🍕 Easy Configuration(ezkfg)

想说一下最近写的一个小项目,ezkfg。

为什么叫这个名呢?主要是因为(kfg,config,cfg,ezcfg,ezconfig)之类的名字都已经被占用了

其次就是,配置文件这个东西总是需求很多的,我在很多项目中都会用到,但是一直没找到一个自己喜欢的。与其不如自己造一个轮子,取其精华去其糟粕。

快来 pip install ezkfg !

几种配置方式

  • argparse:

    最常见的就是 argparse 的方式,支持很多数据类型,支持设置默认值,支持设置可选值,支持设置可选值的描述之类的。这个也是很多项目和我经常使用的方式,尤其是深度学习的项目,因为可以非常方便的指定实验参数。但是参数很难保留,要么就要手写文件读入,要么就在文件中传入 list 先进行参数解析。

  • config.py:

    这是除此上面的方式以外我最喜欢也是常用的形式了吧,因为毕竟是原生的 Python 内容,可以定义多个 config class,然后通过 from config import config_xxx as config 的方式导入,也挺方便配置,同时支持所有 Python 的数据类型。但是毕竟是要修改掉 import 包的信息,每次修改可能都要至少修改两个文件内的参数,容易让人困惑。

  • YAML:

    YAML 也算是非常灵活的配置文件类型,结构简单,而且可以通过文件读入,非常方便复现,支持列表之类的数据结构。是我很喜欢的配置文件类型。

  • json:

    同上,但是文件结构较为复杂,内容多了以后不太直观。

  • ini:

    方便选取多种配置,有内置的库支持,但是是没有数据类型的,读入全是字符串,需要手动进行数据转换,同时是 k-v 形式的,因此是没有层级的。

同时,我又看到了 addict 这个项目,嵌套的 . 进行属性调用真的还挺方便,但是没有文件的 IO。

明确需求

所以,还是要明确一下需求。

文件其实只是个载体,我个人认为文件格式的差异其实都是可以接受的,可能根据应用场景略有差别。比如我想要把我的实验内容发给其他人,或者在其他机器上快速复现,那么我用配置文件的方式显然要比其他方式优秀的多。

另外,在实验中调用的形式也是非常重要的,首先是参数的预加载。预加载时,有些参数我们是需要提供默认值的,而有些参数可能明显用不到,那么最好不要占用存储,简化配置文件的重量。

其次,数据类型是必要的,毕竟在实验中的参数可能是有多种形式的。

然后就是在 Code 中的参数引用,如果对于特定的参数,我希望能够利用嵌套的 . 实现层级的调用,而不是使用一长串的 [] 来调用。但是在另外一些场景,比如两种方法,但是两种方法有着相同的超参数,那么我用 . 来进行调用,很不利于代码的复用,更好的方式是 config['method'].alpha 的形式看起来会更加直观,这样我们就可以动态的修改 method 以使用对应的 alpha 值。因此,这两种形式都是必要的。

最后就是文件 IO 了,这个是必须支持的。如果你要在其他地方部署,显然直接用配置文件,不改动原项目任何代码的效果会好很多。

实现

首当其冲的就是属性调用和索引调用,这两个是必须实现的,而且都要支持嵌套。通过 [] 的索引调用其实没什么好说的,本来就是内置功能,因为在 Python 中每一个类其实都有一个 __dict__ 变量,存储了类中的所有属性。所有的配置参数也是借用了这个字典来进行存储的。

首先是初始化,现在是支持几种初始化方式的,有字典,列表和 Config 类。dict 就需要递归去解决,Config 就用内置的 update 方法即可。

其中 __getitem__ 和 __setitem__ 方法就是用 __getattr__ 和 __setattr__ 调用即可,实现起来也不会有歧义,__setitem__ 方法实现需要先进行分割,然后递归进行即可。但是 __getattr__ 的实现也是很简单,直接递归查询即可。但是 __setattr__ 就不是了,因为在 set 前会先调用 get 方法来进行查询,如果不存在

最后解决文件 IO 的问题。

在 handler 方面,为喜欢自定义的用户提供了注册器,可以直接将自定义的 handler 注册到包中,或者将自定义的文件格式使用已有的 handler 进行解析。

Roadmap

目前项目进行到了 v0.0.1 版本,经过了 3 个 pre-release 版本。

但是肉眼可见的存在一些问题。

首先是目前还不支持数据类型的转换,默认的参数可能只能通过预先入读默认文件或者预先转换 argparse 的形式来实现,在 py 和 ini 文件的接口还有待优化,目前都是 hard code 了名称。

Takeaways

说实话,这个项目确实让我了解了很多配置文件的格式及各自特点,已经 Python 的内置函数和内置函数的调用顺序,比如 __setattr__ 会先调用 __getattr__ 但是并不是在 __setattr__ 中实现的,而是在更高一级实现,所以需要做好处理。

除此之外,更为重要的是方便我自己的项目配置文件书写吧,毕竟很可能没什么人会用 hhh