发布于2026-06-30 阅读(0)
扫一扫,手机访问
argparse 是 Python 标准库里命令行参数解析的利器,几乎每个 CLI 工具都会用到它。它的设计哲学就是“零门槛上手,高阶玩法也能兜住”。从简单的位置参数到复杂的嵌套子命令,一套 API 全搞定。下面我们直接看怎么用。

import argparse
# 创建解析器
## description: 程序说明
## prog: 程序名, 默认为脚本名
## epilog: 帮助信息末尾附加文本
## formatter_class: 控制帮助信息的展示样式
parser = argparse.ArgumentParser(
prog="/my_tool",
description="A simple command-line tool.",
epilog="Example usage: /my_tool 'Hello World' --verbose"
)
# 使用add_argument() 添加参数
# echo1和echo2为位置参数,使用时必需按顺序提供
# type 指定类型转换函数
# help 设置帮助说明
parser.add_argument("echo1", type=str, help="echo something")
parser.add_argument("echo2", type=str, help="echo something")
# -x 或 --xx 为可选参数
# default 设置默认值
parser.add_argument("--sftp_ip",type=str,default="127.0.0.1", help="sftp服务的IP地址")
# 自动转换类型成int
# meta var 修改帮助信息中显示的占位名
parser.add_argument("--sftp_port", meta var="PORT", type=int, default="22")
# dest 指定解析后属性名, 解析后使用 args.username 访问
parser.add_argument("--user-name", dest="username")
# required 让可选参数变成必须提供
# required 只适用于可选参数
parser.add_argument("--name", required=True)
# choice 限制可选值范围
parser.add_argument("-H","--host",type=str, choices=["127.0.0.1", "192.168.0.10"])
# nargs 控制参数个数
## nargs=2, 必须 2 个参数
## nargs='*', 0个或多个参数
## nargs='+', 1个或多个参数
## nargs='?', 0个或1个参数
parser.add_argument('--nums', nargs=3, type=int)
# 创建互斥组,-v和-q不能同时使用
group = parser.add_mutually_exclusive_group()
# action 定义参数行为
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
# 解析参数
# 返回的是一个 Namespace 对象
args = parser.parse_args()
# 使用命令参数
print(f"echo1: {args.echo1}, echo2: {args.echo2}")
print(f"sftp服务的IP为: {args.sftp_ip}, 端口号: {args.sftp_port}")
print(f"host is {args.host}")
argparse 会默认帮你生成 -h 和 --help 选项,省去自己写帮助文档的功夫。需要留意的是,代码里注释部分已经把核心参数解释清楚了,实际使用时可以参照着快速搭建。
add_argument() 中的 action 参数用来定义参数行为。默认值是 store,意味着直接存储值。但更多场景下我们需要一些“特殊动作”,比如布尔开关、累加次数、追加列表等。下面逐个拆解。
action='store_true',常用于布尔开关,不传则为 Falseparser.add_argument('--verbose', action='store_true')
# 运行 python app.py --verbose
# 解析后
args.verbose == True
action='store_false',反向布尔开关,不传则为 Trueaction='append',每出现一次就追加到列表parser.add_argument('--tag', action='append')
# 使用
python app.py --tag a --tag b
# 得到
args.tag == ['a', 'b']
action='count',统计出现次数,常用于日志级别控制parser.add_argument('-v', '--verbose', action='count', default=0)
# 使用
python app.py -vvv
# 得到
args.verbose == 3
action='version',打印版本后退出parser.add_argument('--version', action='version', version='v1.0.0', default=0)
# 使用
python app.py --version
# 输出 v1.0.0
# 也可以写个函数来动态获取
def get_version() -> str:
return "v1.0.0"
# help 不传的话默认为 show program's version number and exit
parser.add_argument(
"--version",
action="version",
version=get_version(),
# help="Show the version of the tool and exit.",
)
action='store_const',设置为指定常量值parser.add_argument('--json', action='store_const', const='json', dest='format')
# 运行
python app.py --json
# 得到
args.format == 'json'
这些 action 组合起来,基本能覆盖 90% 的命令行参数需求。
有时候我们需要让某些参数“水火不容”,比如 --verbose 和 --quiet 同时出现就没意义了。argparse 提供了互斥组来解决:group = parser.add_mutually_exclusive_group()。
使用 group.add_argument 设置的参数将互斥,不能同时使用。如果强行同时传入,argparse 会直接报错。
一个典型例子:
import argparse
parser = argparse.ArgumentParser()
# 创建互斥组
# 传入 required=True 的话,用户必须从互斥组参数中选一个; 默认用户可以不选可选组参数
group = parser.add_mutually_exclusive_group()
group.add_argument('--verbose', action='store_true')
group.add_argument('--quiet', action='store_true')
args = parser.parse_args()
print(args)
# 这样同时调用会报错
python app.py --verbose --quiet
当命令行工具包含多种操作时,子命令就派上用场了。比如一个用户管理工具,可能有 add、delete、list 等子命令,每个子命令又有各自独立的参数。这时 parser.add_subparsers() 就是最佳选择。add_subparsers() 用来给一个命令行程序添加多个子解析器,每个子解析器对应一个子命令。
import argparse
parser = argparse.ArgumentParser(prog='usercli', description='用户管理工具')
# required=True, 强制用户使用子命令
# 建议总是显式写 dest='command'
subparsers = parser.add_subparsers(dest='command', required=True)
# add 子命令
parser_add = subparsers.add_parser('add', help='添加用户')
parser_add.add_argument('username', help='用户名')
parser_add.add_argument('--age', type=int, default=18, help='年龄')
# delete 子命令
parser_delete = subparsers.add_parser('delete', help='删除用户')
parser_delete.add_argument('username', help='用户名')
# list 子命令
parser_list = subparsers.add_parser('list', help='列出用户')
parser_list.add_argument('--verbose', action='store_true', help='显示详细信息')
args = parser.parse_args()
if args.command == 'add':
print(f'添加用户: {args.username}, 年龄: {args.age}')
elif args.command == 'delete':
print(f'删除用户: {args.username}')
elif args.command == 'list':
print(f'列出用户, verbose={args.verbose}')
上面的 if/elif 结构在子命令少时还能用,但一旦命令多起来,代码维护起来就很痛苦。更优雅的做法是:为每个子命令绑定一个处理函数,然后用 set_defaults 把函数存到 func 属性里,最后统一调用 args.func(args)。这样职责清晰,扩展也方便。
import argparse
def handle_add(args):
print(f'添加用户: {args.username}, 年龄: {args.age}')
def handle_delete(args):
print(f'删除用户: {args.username}')
def handle_list(args):
print(f'列出用户, verbose={args.verbose}')
def create_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog='usercli')
subparsers = parser.add_subparsers(dest='command', required=True)
parser_add = subparsers.add_parser('add', help='添加用户')
parser_add.add_argument('username')
parser_add.add_argument('--age', type=int, default=18)
parser_add.set_defaults(func=handle_add)
parser_delete = subparsers.add_parser('delete', help='删除用户')
parser_delete.add_argument('username')
parser_delete.set_defaults(func=handle_delete)
parser_list = subparsers.add_parser('list', help='列出用户')
parser_list.add_argument('--verbose', action='store_true')
parser_list.set_defaults(func=handle_list)
return parser
def main() -> None:
parser = create_parser()
args = parser.parse_args()
# 如果用了 args.func(args)
# 一定要确保每个子命令都执行了 parser_xxx.set_defaults(func=...)
# 否则报错: AttributeError: 'Namespace' object has no attribute 'func'
args.func(args)
if __name__ == "__main__":
main()
不同子命令常常需要重复的参数,比如 --config 配置文件路径。这时候可以抽一个父解析器作为“模板”,通过 parents 参数继承到每个子命令中。注意父解析器要设置 add_help=False,避免帮助信息冲突。
import argparse
def main():
common_parser = argparse.ArgumentParser(add_help=False)
common_parser.add_argument('--config', help='配置文件路径')
parser = argparse.ArgumentParser(prog='tool')
subparsers = parser.add_subparsers(dest='command', required=True)
parser_a = subparsers.add_parser('start', parents=[common_parser])
parser_a.add_argument('--port', type=int)
parser_b = subparsers.add_parser('stop', parents=[common_parser])
parser_b.add_argument('--force', action='store_true')
# 解析命令行参数
# common_parser 是一个共享参数模板, 不需要参与参数解析
args = parser.parse_args()
if args.command == 'start':
print(f"Starting with config: {args.config} on port: {args.port}")
elif args.command == 'stop':
print(f"Stopping with config: {args.config} {'forcefully' if args.force else ''}")
else:
print("Unknown command")
if __name__ == "__main__":
main()
用户可能觉得 remove 太长,想用 rm。通过 aliases 参数可以轻松实现:
parser_remove = subparsers.add_parser('remove', aliases=['rm'])
之后两种命令都可以:
python tool.py remove file.txt python tool.py rm file.txt
一些复杂工具会涉及多级命令,比如 tool user add alice、tool user delete bob。这可以通过嵌套 add_subparsers() 来实现:
import argparse
parser = argparse.ArgumentParser(prog='tool')
subparsers = parser.add_subparsers(dest='entity', required=True)
user_parser = subparsers.add_parser('user')
user_subparsers = user_parser.add_subparsers(dest='action', required=True)
user_add = user_subparsers.add_parser('add')
user_add.add_argument('name')
user_delete = user_subparsers.add_parser('delete')
user_delete.add_argument('name')
args = parser.parse_args()
print(args)
运行 python tool.py user add alice,得到:
Namespace(entity='user', action='add', name='alice')
从基础用法到嵌套、别名、公共参数共享,argparse 的设计足够灵活,能应对从简单脚本到大型 CLI 工具的各种需求。记住一句话:先想清楚你的命令行交互模型,再用 argparse 去实现它,事半功倍。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8