pin_drop当前位置:知识文库 ❯ 图文
Python argparse命令行工具 - 参数解析与子命令完整指南
一、为什么使用argparse
argparse是Python标准库中用于解析命令行参数的模块。相比手动处理sys.argv,argparse提供:
-
自动生成帮助信息:自动生成美观的-h/--help输出
-
参数验证:自动处理类型转换、必选检查、取值范围验证
-
子命令支持:轻松实现类似git的多个子命令
-
错误处理:参数错误时自动显示友好的错误信息和使用说明
二、argparse核心组件
argparse的使用分为四个基本步骤:创建解析器、添加参数、解析参数、使用结果。
代码示例
import argparse
# 1. 创建解析器
parser = argparse.ArgumentParser(
description="这是一个示例命令行工具",
epilog="更多帮助请访问: https://example.com",
formatter_class=argparse.RawDescriptionHelpFormatter
)
# 2. 添加参数
parser.add_argument("filename", help="要处理的文件名")
parser.add_argument("-v", "--verbose", action="store_true", help="显示详细输出")
parser.add_argument("-o", "--output", type=str, default="output.txt", help="输出文件路径")
# 3. 解析参数
args = parser.parse_args()
# 4. 使用解析结果
print(f"处理文件: {args.filename}")
print(f"详细模式: {args.verbose}")
print(f"输出路径: {args.output}")代码示例
# 运行示例
$ python script.py data.csv -v -o result.csv
处理文件: data.csv
详细模式: True
输出路径: result.csv
# 查看帮助
$ python script.py --help
usage: script.py [-h] [-v] [-o OUTPUT] filename
这是一个示例命令行工具
positional arguments:
filename 要处理的文件名
options:
-h, --help show this help message and exit
-v, --verbose 显示详细输出
-o OUTPUT, --output OUTPUT
输出文件路径
更多帮助请访问: https://example.com三、位置参数与可选参数
位置参数
位置参数不需要前缀,按顺序解析,默认是必填的。
代码示例
# 基本位置参数
parser.add_argument("input_file", help="输入文件路径")
# 多个位置参数
parser.add_argument("source", help="源文件")
parser.add_argument("destination", help="目标文件")
# 可选的位置参数(使用?表示0或1个,*表示0或多个,+表示1或多个)
parser.add_argument("files", nargs="*", help="要处理的文件列表")
parser.add_argument("tags", nargs="+", help="至少一个标签")
# 示例:nargs="*" 可以接收0个或多个值
# python script.py file1.txt file2.txt file3.txt
# args.files = ['file1.txt', 'file2.txt', 'file3.txt']
# 示例:nargs="+" 至少需要一个值
# python script.py tag1 tag2
# args.tags = ['tag1', 'tag2']可选参数
可选参数以-或--开头,通常有默认值。
代码示例
import argparse
parser = argparse.ArgumentParser()
# 布尔标志参数
parser.add_argument("-v", "--verbose", action="store_true", help="详细模式")
parser.add_argument("-q", "--quiet", action="store_false", dest="verbose", help="安静模式")
# 带值的参数
parser.add_argument("-c", "--count", type=int, default=1, help="处理次数")
parser.add_argument("-f", "--format", choices=["json", "csv", "xml"], default="json", help="输出格式")
# 必需参数(虽然是可选形式但必须提供)
parser.add_argument("--api-key", required=True, help="API密钥")
# 多个值
parser.add_argument("--tags", nargs="*", help="标签列表")
# 追加模式(可多次使用)
parser.add_argument("--include", action="append", help="包含路径(可多次指定)")
# 使用示例
# python script.py -v --count 5 --format json --api-key abc123 --include /path1 --include /path2四、子命令与参数分组
子命令(Subcommands)
子命令让你可以创建类似git的多功能命令行工具,支持git add、git commit等不同操作。
代码示例
import argparse
def cmd_create(args):
"""创建新项目"""
print(f"创建项目: {args.name}")
print(f"模板: {args.template}")
def cmd_delete(args):
"""删除项目"""
print(f"删除项目: {args.project_id}")
if args.force:
print("强制删除模式")
def cmd_list(args):
"""列出所有项目"""
print(f"显示格式: {args.format}")
if args.verbose:
print("详细信息模式")
def main():
parser = argparse.ArgumentParser(description="项目管理工具")
parser.add_argument("--config", default="config.yaml", help="配置文件路径")
# 创建子命令解析器
subparsers = parser.add_subparsers(dest="command", help="可用命令")
# create子命令
create_parser = subparsers.add_parser("create", help="创建新项目")
create_parser.add_argument("name", help="项目名称")
create_parser.add_argument("-t", "--template", choices=["web", "api", "cli"], default="web", help="项目模板")
create_parser.set_defaults(func=cmd_create)
# delete子命令
delete_parser = subparsers.add_parser("delete", help="删除项目")
delete_parser.add_argument("project_id", help="项目ID")
delete_parser.add_argument("-f", "--force", action="store_true", help="强制删除")
delete_parser.set_defaults(func=cmd_delete)
# list子命令
list_parser = subparsers.add_parser("list", help="列出项目")
list_parser.add_argument("-f", "--format", choices=["table", "json"], default="table", help="输出格式")
list_parser.add_argument("-v", "--verbose", action="store_true", help="显示详细信息")
list_parser.set_defaults(func=cmd_list)
args = parser.parse_args()
if args.command is None:
parser.print_help()
return
# 执行对应命令
args.func(args)
if __name__ == "__main__":
main()代码示例
# 使用子命令
$ python tool.py create myapp --template api
创建项目: myapp
模板: api
$ python tool.py delete 123 --force
删除项目: 123
强制删除模式
$ python tool.py list --format json -v
显示格式: json
详细信息模式参数分组
代码示例
# 将相关参数分组显示,使帮助信息更清晰
parser = argparse.ArgumentParser()
# 输入输出分组
io_group = parser.add_argument_group("输入输出选项")
io_group.add_argument("-i", "--input", required=True, help="输入文件")
io_group.add_argument("-o", "--output", default="out.txt", help="输出文件")
io_group.add_argument("--encoding", default="utf-8", help="文件编码")
# 性能分组
perf_group = parser.add_argument_group("性能选项")
perf_group.add_argument("-j", "--jobs", type=int, default=1, help="并行任务数")
perf_group.add_argument("--buffer-size", type=int, default=4096, help="缓冲区大小")五、完整项目示例
代码示例
#!/usr/bin/env python3
"""data_tool.py - 数据处理命令行工具"""
import argparse
import sys
import json
import csv
from pathlib import Path
def process_csv(input_file: Path, output_file: Path, delimiter: str = ","):
"""处理CSV文件"""
print(f"处理CSV: {input_file} -> {output_file}")
with open(input_file, "r", encoding="utf-8") as f:
reader = csv.reader(f, delimiter=delimiter)
rows = list(reader)
print(f"读取 {len(rows)} 行数据")
with open(output_file, "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerows(rows)
print("处理完成")
def process_json(input_file: Path, output_file: Path, pretty: bool = False):
"""处理JSON文件"""
print(f"处理JSON: {input_file} -> {output_file}")
with open(input_file, "r", encoding="utf-8") as f:
data = json.load(f)
print(f"读取 {len(data) if isinstance(data, list) else 1} 条数据")
with open(output_file, "w", encoding="utf-8") as f:
if pretty:
json.dump(data, f, indent=2, ensure_ascii=False)
else:
json.dump(data, f, ensure_ascii=False)
print("处理完成")
def main():
parser = argparse.ArgumentParser(
description="数据处理命令行工具",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例用法:
%(prog)s convert input.csv output.json --from csv --to json
%(prog)s convert input.json output.csv --pretty
"""
)
parser.add_argument("-v", "--verbose", action="store_true", help="详细输出")
parser.add_argument("--version", action="version", version="data_tool 1.0.0")
subparsers = parser.add_subparsers(dest="command", required=True, help="可用命令")
# convert命令
convert_parser = subparsers.add_parser("convert", help="转换文件格式")
convert_parser.add_argument("input", type=Path, help="输入文件")
convert_parser.add_argument("output", type=Path, help="输出文件")
convert_parser.add_argument("--from", dest="input_format", choices=["csv", "json"], required=True, help="输入格式")
convert_parser.add_argument("--to", dest="output_format", choices=["csv", "json"], required=True, help="输出格式")
convert_parser.add_argument("--delimiter", default=",", help="CSV分隔符")
convert_parser.add_argument("--pretty", action="store_true", help="格式化JSON输出")
convert_parser.set_defaults(func=lambda args: handle_convert(args))
args = parser.parse_args()
if args.verbose:
print(f"参数: {vars(args)}")
args.func(args)
def handle_convert(args):
"""处理convert命令"""
if args.input_format == "csv" and args.output_format == "json":
# CSV转JSON
import csv
with open(args.input, "r", encoding="utf-8") as f:
reader = csv.DictReader(f, delimiter=args.delimiter)
data = list(reader)
with open(args.output, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2 if args.pretty else None, ensure_ascii=False)
elif args.input_format == "json" and args.output_format == "csv":
# JSON转CSV
with open(args.input, "r", encoding="utf-8") as f:
data = json.load(f)
if data:
with open(args.output, "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
print(f"转换完成: {args.input} -> {args.output}")
if __name__ == "__main__":
main()代码示例
# 运行示例
$ python data_tool.py --help
$ python data_tool.py convert data.csv output.json --from csv --to json
$ python data_tool.py convert data.json output.csv --from json --to csv --pretty
$ python data_tool.py --version六、注意事项与最佳实践
注意1:使用
required=True在子命令中时,如果没有提供任何子命令,argparse会自动显示错误并退出。在Python 3.7+中支持此参数,更早版本需要手动检查args.command is None。
注意2:参数命名推荐使用短选项(-v)配合长选项(--verbose)的方式。短选项方便快速输入,长选项提高脚本可读性。使用
dest参数可以自定义解析后的属性名。
小贴士:type参数的妙用
type不仅可以是int、float等内置类型,还可以是任意可调用对象。例如type=Path自动将字符串转为Path对象,type=argparse.FileType("r")自动打开文件。你还可以传入自定义验证函数进行复杂校验。
七、小结
-
使用argparse替代sys.argv:自动帮助、验证、错误处理
-
位置参数和可选参数:位置参数必填按序解析,可选参数以-/--开头有默认值
-
子命令:使用add_subparsers()创建多功能CLI工具
-
参数分组:使用add_argument_group()组织帮助信息
八、练习题
练习1
编写一个文件批处理命令行工具,支持rename、compress、encrypt三个子命令,每个子命令有各自的参数选项,并生成清晰的帮助信息。
练习2
为你的工具添加自定义类型验证函数,验证输入文件是否存在、输出目录是否可写、端口号是否在有效范围(1-65535)内。
常见问题
argparse和click/typer有什么区别?
argparse是Python标准库内置模块,无需安装额外依赖,适合简单到中等复杂度的CLI。click和typer是第三方库,语法更简洁优雅,支持装饰器定义命令,适合复杂的CLI工具。如果项目简单且不想引入外部依赖,argparse是首选;如果需要丰富的CLI体验,推荐使用click或typer。
如何处理互斥参数?
使用add_mutually_exclusive_group()创建互斥组。例如:group = parser.add_mutually_exclusive_group(); group.add_argument("--verbose", action="store_true"); group.add_argument("--quiet", action="store_true")。这样--verbose和--quiet不能同时使用,argparse会自动处理冲突并报错。
如何将argparse与配置文件结合使用?
可以在parse_args()后读取配置文件,用命令行参数覆盖配置文件值。或者使用configargparse第三方库,它原生支持配置文件+环境变量+命令行参数的优先级合并。推荐优先级:命令行参数 > 环境变量 > 配置文件 > 默认值。
本文涉及AI创作
内容由AI创作,请仔细甄别