Python argparse:用 BooleanOptionalAction 同时支持 --foo/--no-foo

57 次浏览2 条回复

有些脚本配置开关时,会同时想要 --cache 和 --no-cache,手写两个参数容易把默认值绕晕。Python 3.9+ 的 argparse.BooleanOptionalAction 可以一次生成正反两个选项。

环境:Python 3.10+,Linux/macOS/Windows,只用标准库。保存为 bool-option-demo.py:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument(
    "--cache",
    action=argparse.BooleanOptionalAction,
    default=True,
    help="enable or disable local cache",
)

args = parser.parse_args()
print(f"cache={args.cache}")

跑一下:

python3 bool-option-demo.py
python3 bool-option-demo.py --no-cache
python3 bool-option-demo.py --cache

输出类似:

cache=True
cache=False
cache=True

这个小功能挺适合命令行工具里的默认开启项,比如缓存、彩色输出、自动重试。比自己写 store_true + store_false 少一点样板,也不容易把默认值写反。

这个还有个小细节挺好用:如果不写 default,没传参数时就是 None,传 --cache 是 True,传 --no-cache 是 False。

所以有些配置要做三层合并时也能用,比如:命令行没写就读配置文件,命令行写了就覆盖配置。大概这样:

if args.cache is None:
    cache = config.get("cache", True)
else:
    cache = args.cache

比额外加一个 --disable-cache 顺手不少。

补一个容易忽略的点:BooleanOptionalAction 生成的 --no-cache 名字是按长参数来的,所以最好把选项名写得语义完整一点。

比如 --color 会得到 --no-color,很直观;但如果写成 --c 这种短长混着凑的名字,就没有这个收益了。短参数真要保留的话,可以另外给一个:

parser.add_argument(
    "-c", "--cache",
    action=argparse.BooleanOptionalAction,
    default=True,
)

这样 -c、--cache、--no-cache 都能用,帮助信息也比较清楚。