1. 最小CLI骨架与参数解析
为什么从“最小骨架”开始
一个可用的 CLI 程序,最小闭环只需要三件事:接收参数 → 解析参数 → 根据参数执行动作。Python 标准库的 argparse 已经把这套机制封装好了,我们不需要引入任何第三方依赖,就能得到一个带帮助信息、错误提示和退出码的可执行程序。
本例的目标是写出一个 greet 命令:它接受一个位置参数 name,以及一个可选参数 --times(默认 1 次),并支持 -h/--help 自动输出帮助信息。
参数解析的职责边界
在动手写代码之前,先看清 argparse 在程序中的位置。它不负责业务逻辑,只负责把命令行字符串翻译成 Python 对象,并处理“用户输入不合法”时的报错与退出。
完整可运行代码
下面这段代码可以直接保存为 greet.py 并运行。它不依赖任何第三方库,Python 3.6+ 均可执行。
#!/usr/bin/env python3
"""最小 CLI 骨架:位置参数 + 可选参数 + 自动帮助。"""
import argparse
import sys
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="greet",
description="向指定名字打招呼,可重复多次。",
epilog="示例:greet Alice --times 3",
)
# 位置参数:必须提供
parser.add_argument(
"name",
help="要打招呼的名字",
)
# 可选参数:有默认值
parser.add_argument(
"-t", "--times",
type=int,
default=1,
help="重复次数(默认 1)",
)
return parser
def main(argv=None) -> int:
parser = build_parser()
args = parser.parse_args(argv)
if args.times < 1:
parser.error("--times 必须大于等于 1")
for _ in range(args.times):
print(f"Hello, {args.name}!")
return 0
if __name__ == "__main__":
sys.exit(main())
运行与验证
把文件保存后,依次执行以下命令,观察输出是否符合预期:
| 命令 | 预期输出 | 退出码 |
|---|---|---|
python greet.py Alice |
Hello, Alice! |
0 |
python greet.py Alice --times 3 |
三行 Hello, Alice! |
0 |
python greet.py -h |
打印 usage、位置参数、可选参数说明 | 0 |
python greet.py |
报错:the following arguments are required: name | 2 |
python greet.py Alice --times 0 |
报错:--times 必须大于等于 1 | 2 |
验证要点:退出码是 CLI 程序契约的一部分。正常执行返回 0,参数错误返回 2(argparse 默认行为),业务校验失败也返回 2。这样脚本可以被其他程序可靠地调用和判断。
关键设计点
- prog 参数:显式指定程序名,避免帮助信息里出现
greet.py这种带扩展名的路径。 - type=int:让 argparse 在解析阶段就完成类型转换,非法输入(如
--times abc)会自动报错,业务代码不需要再做字符串转换。 - default=1:可选参数不传时使用默认值,保证
args.times始终是整数。 - parser.error():业务层校验失败时调用它,会打印错误信息并以退出码 2 结束,保持与参数错误一致的对外行为。
- main(argv=None):把参数列表作为可选入参,方便后续写单元测试时直接传入
["Alice", "--times", "2"],而不必真的启动子进程。
最小骨架的边界:本例只处理“单命令 + 位置参数 + 可选参数”。当需要
greet add、greet list 这类多命令结构时,就需要引入子命令路由,那是下一个案例要解决的问题。