使用 argparse 构建 CLI
用标准库 argparse 做可测试 CLI:参数解析、退出码与业务函数分离。
#howto
#growing
#dev
#python
#python
[!info] Related notes
使用 argparse 构建 CLI
目标
交付一个可本地运行的命令行工具:解析参数、调用纯业务函数、以退出码表达成功/失败。
这个场景为什么出现
运维与数据同学需要“一条命令完成任务”。把解析与业务混在一起会导致无法单测。
[!abstract] 一句话理解 argparse 负责 argv → 结构化参数;业务函数可测;
main映射到退出码。
最小可运行示例
场景:订单号规范化小工具
本例约定订单号去掉首尾空白后转大写。这只是示例业务规则;真实标识符若区分大小写,不能直接套用。Unicode 大写转换也可能改变字符数量,如 ß 变为 SS。
# normalize_order_cli.py
# 业务意图:CLI 规范化订单号。
# 教学点:ArgumentParser;业务纯函数;退出码。
from __future__ import annotations
import argparse
import sys
def normalize_order_id(raw: str) -> str:
value = raw.strip().upper()
if not value:
raise ValueError("order id is empty")
return value
def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(description="Normalize order id")
p.add_argument("order_id", help="raw order id")
return p
def main(argv: list[str] | None = None) -> int:
args = build_parser().parse_args(argv)
try:
print(normalize_order_id(args.order_id))
return 0
except ValueError as exc:
print(f"error: {exc}", file=sys.stderr)
return 2
if __name__ == "__main__":
raise SystemExit(main())
将代码保存为 normalize_order_cli.py 后运行(使用支持示例类型注解的现代 Python,例如 3.10+):
python normalize_order_cli.py " ab-1 "
python normalize_order_cli.py " "; echo exit:$?
期望输出:
AB-1
error: order id is empty
exit:2
--help 输出帮助到 stdout 并以 0 退出;缺少参数/未知选项由 argparse 向 stderr 输出用法错误并以 2 退出。这两条路径会在 parse_args 内抛出 SystemExit,不会经过后面的业务异常处理。订单号以 - 开头时,用 python normalize_order_cli.py -- -ab-1 分隔选项,输出 -AB-1。
结合场景再看三个关注点
main(argv)便于测试注入。- 退出码给 shell/CI 用。
- 复杂 CLI 可迁 Typer/click,但标准库足够多场景。
步骤清单
- 抽纯函数
- 定义 parser
- main 映射错误
- 可选打包入口
验收标准
-
--help输出帮助并以 0 退出 - 成功 stdout、失败 stderr 与退出码正确
- 业务函数可独立调用;main 可注入 argv,解析错误需捕获 SystemExit
2026-10-07:使用 Python 3.12.3 提取本页脚本,验证成功、空白、缺参、多参、未知选项、帮助与 -- 分隔路径,并独立调用业务函数。
本节总结
CLI 是函数的外壳。标准库 argparse 足够起步。
自测题
- 为何 main 返回 int?
- 业务异常如何呈给用户?
参考答案
- 表达进程退出码。
- 捕获后写 stderr 并返回非 0。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| argparse | 文档 | 官方 |