用 argparse 是 python 命令行程序可维护的底线;应规范使用 add_argument()、subparsers、type/action 校验,业务逻辑须解耦至独立函数,用 logging 替代 print,并正确配置 entry_points。

用 argparse 而不是 sys.argv 手撕参数
手写 sys.argv 解析很快会失控,尤其当参数变多、要支持 --help、类型校验、子命令时,逻辑迅速变成面条。用 argparse 是 Python 命令行程序可维护的底线。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 把每个参数定义为独立的
add_argument()调用,别堆在一行里;命名用dest显式指定变量名,避免靠位置猜含义 - 对必填参数加
required=True,别靠运行时报错提醒用户;对布尔开关用action='store_true',而不是手动转字符串 - 子命令(如
mytool init/mytool run)必须用add_subparsers()+set_defaults(func=...),否则分支逻辑会散落在 if 判断里,难以测试和复用 - 别在
parse_args()后再做参数合法性检查(比如“--port必须大于 1024”),应该用type=或自定义action提前拦截——错误信息才准确,用户才不会看到AttributeError
把业务逻辑从 main() 函数里彻底移出去
常见错误是把所有代码塞进 if __name__ == '__main__': 下面:打开文件、调 API、格式化输出全混在一起。这种写法导致无法单元测试、无法复用、无法调试单个环节。
实操建议:
立即学习“Python免费学习笔记(深入)”;
-
main()函数只做三件事:解析参数 → 调用一个顶层函数(如run_cli(args))→ 捕获并打印顶层异常 - 每个核心能力单独成函数,接收明确输入、返回明确值,不读环境变量、不直接 print;例如
fetch_user(user_id: str) -> dict,而不是do_the_thing() - 如果涉及 I/O,把路径、URL、超时等作为参数传入,而不是硬编码或从全局配置读;这样本地测试时才能 mock 或替换为临时文件
- 避免在函数里调
exit()或print()—— 错误由main()统一处理,成功结果由调用方决定怎么展示
用 logging 替代 print() 控制输出粒度
上线后需要看日志定位问题,但满屏 print('step 2 done') 既没法关、又分不清优先级,还会污染 JSON 输出流。用 logging 是唯一合理选择。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 初始化只调一次
logging.basicConfig(),在main()开头,格式带时间、级别、模块名;别在每个文件里重复配置 - DEBUG 级别只放开发期诊断信息(如“收到 raw payload: {...}”),INFO 放用户关心的进度(如“已同步 127 条记录”),WARNING 和 ERROR 严格对应异常分支,别滥用
- CLI 工具默认日志级别设为
INFO,通过--verbose参数动态设为DEBUG,别让用户改代码 - 别用
logging.info('user %s, id %d' % (name, uid))拼接字符串——用logging.info('user %s, id %d', name, uid),避免格式错误时日志直接崩掉
打包前先确认 entry_points 和 console_scripts 是否生效
很多工具本地能跑,pip install 后却提示 command not found,根本原因是没正确注册入口点,或者安装时跳过了 setup.py / pyproject.toml 中的声明。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 在
pyproject.toml中写清楚:[project.entry-points."console_scripts"]下映射命令名到模块函数,例如mytool = "mytool.cli:main" - 安装必须用
pip install -e .(开发模式)或pip install .,不能只运行python mytool/cli.py就以为完事 - 装完立刻验证:
which mytool应该返回路径,mytool --help应该正常输出——别等到 CI 报错才回头查 - Windows 用户注意:某些终端(如 Git Bash)可能缓存旧的命令路径,改完
entry_points后要关掉终端重开,否则始终找不到新命令
最常被忽略的是子命令的函数绑定——set_defaults(func=...) 里的函数必须可被 import,路径写错、模块没 __init__.py、或者函数在 if 块里定义,都会让命令静默失败,只显示空 help。










