这里有一个支持子命令的扩展版本,以及一个示例脚本。
模板
好了
#!/usr/bin/env python
from __future__ import annotations
import argparse
from collections.abc import Sequence
def main(argv: Sequence[str] | None = None) -> int:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="command", required=True)
# Add sub-commands
subcommand1_parser = subparsers.add_parser("subcommand1", help="...")
subcommand1_parser.add_argument("string")
args = parser.parse_args(argv)
if args.command == "subcommand1":
return subcommand1(args.string)
else:
# Unreachable
raise NotImplementedError(
f"Command {args.command} does not exist.",
)
def subcommand1(string: str) -> int:
# Implement behaviour
return 0
if __name__ == "__main__":
raise SystemExit(main())
这可以在Python 3.7以上版本中使用:
以下是与vanilla模板的不同之处。
-
add_subparsers()我们告诉它存储命令的名字以便以后进行比较,并使命名一个子命令成为必要。 -
我们用
subparsers.add_parser(),为每个子命令添加解析器,它返回一个ArgumentParser。我们可以用它以正常的方式添加参数。(...甚至可以通过调用它的add_subparsers(),配置子子命令。 -
在参数解析之后,我们使用
if来打开args.command中的子命令名称,并调用相应的子命令函数。我们在调用时解构args,这样我们的子命令函数就可以接受精确的类型。用
if进行切换,比argparse文档中首先提到的方法要好。set_defaults(func=...)argparse文档中首先提到的方法。使用if,可以保持控制流的清晰,而且这意味着我们的子命令函数可以接受带有类型的单个参数,而不是args。 -
我们的
else块对未识别的子命令提出了一个错误。 这在通常情况下是达不到的--argparse已经退出了,对未知的子命令发出了信息。$ ./example.py subcommand2 usage: example.py [-h] {subcommand1} ... example.py: error: argument command: invalid choice: 'subcommand2'(choose from 'subcommand1')但如果我们添加了一个子命令解析器,并错过了其对应的
if块,这个错误就会成为可能。 所以最好是保留它。为了支持没有子命令的使用,从
add_subparsers()调用中删除required=True,并在这个else块中添加行为。
举例来说
这里我们有两个子命令,debug 和hello 。
#!/usr/bin/env python
from __future__ import annotations
import argparse
import sys
from collections.abc import Sequence
def main(argv: Sequence[str] | None = None) -> int:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="command", required=True)
subparsers.add_parser("debug", help="Show debug information.")
hello_parser = subparsers.add_parser("hello", help="Say hello.")
hello_parser.add_argument("name", help="Who to greet.")
args = parser.parse_args(argv)
if args.command == "debug":
return debug()
elif args.command == "hello":
return hello(name=args.name)
else:
raise NotImplementedError(
f"Command {args.command} does not exist.",
)
def debug() -> int:
print(f"Python version {sys.version}")
return 0
def hello(name: str) -> int:
print(f"Hello {name}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
酷......让我们试试吧。
我们可以请求帮助,而argparse也会答应。
$ ./example.py -h
usage: example.py [-h] {debug,hello} ...
positional arguments:
{debug,hello}
debug Show debug information.
hello Say hello.
optional arguments:
-h, --help show this help message and exit
我们也可以得到子命令的帮助。
$ ./example.py hello --help
usage: example.py hello [-h] name
positional arguments:
name Who to greet.
optional arguments:
-h, --help show this help message and exit
debug 这个子命令很简单。
$ ./example.py debug
Python version 3.9.7 (default, Sep 1 2021, 11:36:38)
[Clang 12.0.5 (clang-1205.0.22.11)]
而hello ,如预期的那样工作。
$ ./example.py hello reader
Hello reader
非常酷