当你需要把一段 Python 脚本变成可复用的命令行工具时,不可避免地要处理用户从终端输入的参数。Python 标准库中的 argparse 模块就是专门做这件事的,它让参数解析变得简单、规范,并且自动生成友好的帮助文档。
为什么用 argparse
直接读 sys.argv 也能拿到命令行参数,但需要手动解析、校验、打印帮助信息,代码很快就会变得杂乱。argparse 帮你自动完成这些工作:
- 定义参数的名字、类型、默认值、是否必需。
- 自动检查参数是否合法,并输出清晰的错误提示。
- 根据参数定义自动生成
--help帮助信息。
快速上手
一个最简单的例子:
import argparse
parser = argparse.ArgumentParser(description='一个示例工具')
parser.add_argument('filename', help='要处理的文件名')
args = parser.parse_args()
print(f'处理文件: {args.filename}')
保存为 tool.py,然后在终端执行:
python tool.py data.txt
就会输出 处理文件: data.txt。如果直接运行不加参数,argparse 会自动提示缺少参数。
位置参数与可选参数
- 位置参数:像上文
filename这样不加-前缀的,必须按顺序提供。 - 可选参数:以
-或--开头,可以用-o value或--output value的形式指定。
parser.add_argument('-o', '--output', help='输出文件路径')
类型、默认值与必选
- type:指定参数的类型,默认是字符串。可以设为
int、float或自定义函数。 - default:不传该参数时的默认值,如果不设置则默认为
None(可选参数)或必须由用户提供(位置参数)。 - required:对于可选参数,可以设置
required=True强制用户必须提供。
parser.add_argument('--count', type=int, default=1, help='重复次数')
parser.add_argument('--name', required=True, help='你的名字')
常用的 action
action 控制参数如何被存储。
'store':默认,保存后面的值。'store_true'/'store_false':常用于布尔开关,带上参数即为True,不带就是False。'append':允许多次指定,将值存入列表。
parser.add_argument('--verbose', action='store_true', help='详细输出')
parser.add_argument('--exclude', action='append', help='排除文件(可多次指定)')
调用 python tool.py --verbose 后,args.verbose 就是 True。
互斥参数组
有时需要强制用户只能在几个选项中选择一个,可使用互斥组。
group = parser.add_mutually_exclusive_group()
group.add_argument('--start', help='开始时间')
group.add_argument('--restart', action='store_true', help='重新开始')
这样用户就不能同时使用 --start 和 --restart。
解析与错误处理
parser.parse_args()返回一个命名空间对象,你可以通过args.参数名访问值。- 如果用户传入了未定义的参数,
argparse会报错并提示正确用法;如果参数类型不对(比如给--count传了字符串),也会自动抛出错误。
脚本工具开发示例
一个批量重命名文件的工具:
import argparse
import os
def main():
parser = argparse.ArgumentParser(description='批量添加文件名前缀')
parser.add_argument('directory', help='目标目录')
parser.add_argument('--prefix', default='new_', help='要添加的前缀,默认 new_')
parser.add_argument('--dry-run', action='store_true', help='只显示计划,不真正执行')
args = parser.parse_args()
for filename in os.listdir(args.directory):
old_path = os.path.join(args.directory, filename)
if not os.path.isfile(old_path):
continue
new_name = args.prefix + filename
new_path = os.path.join(args.directory, new_name)
if args.dry_run:
print(f'[DRY RUN] {filename} -> {new_name}')
else:
os.rename(old_path, new_path)
print(f'重命名: {filename} -> {new_name}')
if __name__ == '__main__':
main()
执行时可以通过 --prefix 自定义前缀,用 --dry-run 先预览操作。
最佳实践小结
- 一定要设置
description或epilog,给工具一个清晰的说明。 - 尽量提供实用的
default,减少必须的参数。 - 使用
type和choices(例如choices=['a', 'b'])做输入校验,避免后续代码里再判断。 - 对于复杂的子命令(如
git commit、git push),可以使用add_subparsers()实现,但通常小工具暂时用不到。 - 最终的命令行工具,可在
if name == 'main':中调用主函数,以便模块也可以被导入使用。
掌握 argparse 后,几乎所有 Python 脚本都可以快速升级成专业、好用的命令行工具,无论是自己使用还是交付给同事、运维,体验都会大幅提升。