项目模式(六)—— 可执行过程及其配置参数
• 27 October 2019
这里要讲述的是一种运行子指令及其参数、配置的实践。该部分描述了我在2018年写的一个机器学习框架中相应的实现。 是复杂程序配置大量运行参数的一种实践。
分析
- 对于负责系统,程序的运行往往需要非常大量的运行时参数。这些参数的管理往往会有很多问题。
- 关于程序运行参数要防止过设计。其针对一个命令(或子命令)来说应该是确定有限的。不能根据环境或者运行情况动态变化。
- 配置参数应该有的基本功能:名,类型(整数、浮点数、字符串),默认值,描述。
功能
(一)编码时
- 希望能够有一个可复用逻辑,简单的将所有配置参数这个过程抽象出来。
- 希望可以执行多个相关的子指令。
- 多个子指令可能有部分参数是共享的。这个库应该可以处理不同入口的参数共享。
- 自动“帮助”(–help)
(二)执行时
- 由于参数过多,很难每次运行的时候指定所有参数,希望可以把参数保存到配置文件中,用配置文件运行。
- 上述配置文件不要手写构建,这样很可能出现typo。因此生成模板配置文件也是需要的功能。
- 希望能够继承某一次运行的参数,通过改动其中的一些构造新的配置文件。
- 通过某个配置文件运行,但是在运行时临时在命令行中设置一些临时参数。
实现
功能示例:
from dlab.config import add_config
@add_config('config_name1', int, default=1, desc='help information for config_name1')
@add_config('config_name2', str, default='', desc='help information for config_name1')
def func_1(config):
print(config['config_name1'], config['config_name2']) # 通过名字来进行访问,config这个参数是调用时自动注入的。
@inherit_config(func_1)
@add_config('config_name3', int, default=1, desc='help information for config_name3')
def func_2(config):
func_1() # config这个参数是调用时自动注入的。在调用时不需要传入。
print(config['config_name1'], config['config_name2']) # 继承子过程可以调用到父过程的配置,反之不能。
print(config['config_name3'])
实现参见 dlab/dlab/config.py
浅谈与静态分层配置的区别
这里与模式二说的内容是有一定的冲突的,下面我们会分析在什么情况下应该使用怎样的设计思路。
- 分层配置是和项目所有模块相关的,缺点是,每个模块都需要明确知晓有配置(常量)这个模块存在,并且详细了解其结构,内容。但是本文配置模式提倡的是将运行参数延迟到定义运行过程的时候再指定,运行过程中将决定如何用参数去构造和执行其包含的子过程,子过程一般采用常用的函数调用模式和函数传参方法,但是其缺点是运行过程需要明确了解其调用的子过程的构造和调用细节。综上,前者是包结构,内聚,提供简单接口,配置分层。后者是对复杂过程的封装,接口丰富,统一配置。在不同的情况下可以自行考虑使用哪种模式。