拿之前写过的项目来
篇 post 捏
Why
你是否在写 python 脚本(跑实验等)时遇到这种问题:
- Problem 1
-
脚本需要传入若干参数。这种参数先用
dataclass/pydantic定义一个class Config,需要指定一次类型和默认值;然后再用argparse的时候又要再指定一次类型和参数; - Problem 2
-
argparse无法轻松地嵌套Config。比如整个脚本有一个总体的Config,脚本分为三个模块 train, evaluate, plot, 分别使用TrainConfig,EvalConfig,PlotConfig。要给它们分别加上argparse配置的话,很难区分它们。
What
为了解决以上问题,我开发了 lunaconf 库(pypi, GitHub)。
它主要支持以下内容:
- 你只需定义一次
Config,即可自动使用lunaconf的命令行接口调整参数; - 支持嵌套的
Config和嵌套的数组。 - 支持
pydantic的全部功能,比如默认参数、alias、输入约束检查等。
How to use it
使用方法很简单:直接将 lunaconf>=0.5.2 加入依赖即可:
$ uv add lunaconf
下面举个比较完整的例子:比如我这个脚本有 Train 和 Plot 两个子模块,Train 模块中可能输入一个 list 的 Engine 配置。
from lunaconf import LunaConf, lunaconf_cli
from pydantic import Field
class TrainEngineConfig(LunaConf):
name: str
class TrainConfig(LunaConf):
engines: list[TrainEngineConfig] = Field(default_factory=list)
learning_rate: float = 0.01
class PlotConfig(LunaConf):
columns: int = 2
class Config(LunaConf):
train: TrainConfig = Field(default_factory=TrainConfig)
plot: PlotConfig = Field(default_factory=PlotConfig)
if __name__ == "__main__":
config = lunaconf_cli(Config)
print(repr(config))
# do other things
这时尝试运行这个脚本,可以看到打印的参数
Config(train=TrainConfig(engines=[], learning_rate=0.01), plot=PlotConfig(columns=2))
然后简要介绍命令行使用方法:你可以使用如下参数来修改值,比如我要使用三列而非两列
$ python3 main.py \
plot.columns=3
Config(train=TrainConfig(engines=[], learning_rate=0.01), plot=PlotConfig(columns=3))
还可以使用 .0 等来访问数组,并使用 json 语法来创建一个比较大的对象:
$ python main.py train.engines.0='{ "name": "vllm" }'
Config(train=TrainConfig(engines=[TrainEngineConfig(name='vllm')], learning_rate=0.01), plot=PlotConfig(columns=2))
同时,还可以用 -T, -J 参数读入已存在的 toml/json 文件,用 -p, -P 参数将当前配置用 toml/json 输出并退出。
除此以外,还有在配置时读入环境变量/读入特殊值(如 NaN 等)的功能。当你想用到时,可以仔细阅读项目的 README.md 文档!