Python argparse - 向多个子解析器添加参数
Posted
技术标签:
【中文标题】Python argparse - 向多个子解析器添加参数【英文标题】:Python argparse - Add argument to multiple subparsers 【发布时间】:2011-11-21 20:27:22 【问题描述】:我的脚本定义了一个主解析器和多个子解析器。我想将 -p
参数应用于一些子解析器。到目前为止,代码如下所示:
parser = argparse.ArgumentParser(prog="myProg")
subparsers = parser.add_subparsers(title="actions")
parser.add_argument("-v", "--verbose",
action="store_true",
dest="VERBOSE",
help="run in verbose mode")
parser_create = subparsers.add_parser ("create",
help = "create the orbix environment")
parser_create.add_argument ("-p",
type = int,
required = True,
help = "set db parameter")
# Update
parser_update = subparsers.add_parser ("update",
help = "update the orbix environment")
parser_update.add_argument ("-p",
type = int,
required = True,
help = "set db parameter")
如您所见,add_arument ("-p")
重复了两次。我实际上有更多的子解析器。有没有办法遍历现有的子解析器以避免重复?
为了记录,我使用的是 Python 2.7
【问题讨论】:
相关:***.com/questions/14918804/… 【参考方案1】:这可以通过定义一个包含常用选项的parent parser 来实现:
import argparse
parent_parser = argparse.ArgumentParser(description="The parent parser")
parent_parser.add_argument("-p", type=int, required=True,
help="set db parameter")
subparsers = parent_parser.add_subparsers(title="actions")
parser_create = subparsers.add_parser("create", parents=[parent_parser],
add_help=False,
description="The create parser",
help="create the orbix environment")
parser_create.add_argument("--name", help="name of the environment")
parser_update = subparsers.add_parser("update", parents=[parent_parser],
add_help=False,
description="The update parser",
help="update the orbix environment")
这会产生以下格式的帮助消息:
parent_parser.print_help()
输出:
usage: main.py [-h] -p P create,update ...
The parent parser
optional arguments:
-h, --help show this help message and exit
-p P set db parameter
actions:
create,update
create create the orbix environment
update update the orbix environment
parser_create.print_help()
输出:
usage: main.py create [-h] -p P [--name NAME] create,update ...
The create parser
optional arguments:
-h, --help show this help message and exit
-p P set db parameter
--name NAME name of the environment
actions:
create,update
create create the orbix environment
update update the orbix environment
但是,如果您运行程序,如果您不指定操作(即create
或update
),则不会遇到错误。如果您需要这种行为,请按如下方式修改您的代码。
<...>
subparsers = parent_parser.add_subparsers(title="actions")
subparsers.required = True
subparsers.dest = 'command'
<...>
此修复是在 this SO question 中提出的,它指的是跟踪拉取请求的问题。
@hpaulj 更新
由于自 2011 年以来处理子解析器的变化,将主解析器用作 parent
是一个坏主意。更一般地说,不要尝试在主解析器和子解析器中定义相同的参数(相同的dest
)。子解析器的值将覆盖主解析器设置的任何内容(即使是子解析器default
也会这样做)。创建单独的解析器以用作parents
。如文档所示,家长应使用add_help=False
。
【讨论】:
来自the docs:“当从子解析器请求帮助消息时,只会打印该特定解析器的帮助。帮助消息将不包括父解析器或兄弟解析器消息。”这似乎是该策略的一个主要缺点。 我最终向根解析器添加了一个虚拟参数,并带有一条帮助消息。 @RyneEverett:该手册部分令人困惑并且可能已经过时,因为至少在 Python 3.5.3 子解析器--help
中似乎包含来自父解析器的参数。
我已经编辑了答案,显示了父子解析器的--help
输出。请注意create
的帮助消息同时显示“创建”和所有操作,这是不正确的。循环答案不会受到这个问题的影响
我认为它表现异常的原因是“父解析器”实际上与“带有子解析器的解析器”不同。 (请注意,文档从不显示一起使用的两个功能)很确定您需要一个***解析器,一个单独的“父”解析器,上面有全局参数,以及前者的子解析器,它们的 parents=
设置为后者.【参考方案2】:
accepted answer 是正确的;正确的方法是使用parent parsers。但是,示例代码 IMO 并没有真正解决问题。让我加上我的几分钱来提供一个更合适的例子。
与接受的答案的主要区别是明确可能有一些根级参数(如--verbose
)以及仅用于一些子解析器的共享参数(-p
仅用于@ 987654327@ 和 update
子解析器,但不适用于其他)
# Same main parser as usual
parser = argparse.ArgumentParser()
# Usual arguments which are applicable for the whole script / top-level args
parser.add_argument('--verbose', help='Common top-level parameter',
action='store_true', required=False)
# Same subparsers as usual
subparsers = parser.add_subparsers(help='Desired action to perform', dest='action')
# Usual subparsers not using common options
parser_other = subparsers.add_parser("extra-action", help='Do something without db')
# Create parent subparser. Note `add_help=False` and creation via `argparse.`
parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument('-p', help='add db parameter', required=True)
# Subparsers based on parent
parser_create = subparsers.add_parser("create", parents=[parent_parser],
help='Create something')
# Add some arguments exclusively for parser_create
parser_update = subparsers.add_parser("update", parents=[parent_parser],
help='Update something')
# Add some arguments exclusively for parser_update
这是***帮助消息(注意这里没有显示-p
参数,这正是您所期望的——因为它特定于某些子解析器):
>>> parser.print_help()
usage: [-h] [--verbose] extra-action,create,update ...
positional arguments:
extra-action,create,update
Desired action to perform
extra-action Do something without db
create Create something
update Update something
optional arguments:
-h, --help show this help message and exit
--verbose Common top-level parameter
以及create
操作的帮助消息:
>>> parser_create.print_help()
usage: create [-h] -p P
optional arguments:
-h, --help show this help message and exit
-p P add db parameter
【讨论】:
因此,在我之前对主要答案的编辑中,我在parent
解析器中包含了“-p”选项,以显示用户如何在所有子解析器之间拥有通用选项。然后我展示了一个“--name”选项可以添加到单个subparser
,这是create
命令/操作所独有的。我们解决方案的主要区别在于帮助的显示方式。这里是my output,这里是your output。
我完全同意,这不是必需的,但有些人可能想混合使用两者。您的帮助消息绝对更干净,感谢添加!
单独的父解析器是在多个子命令之间共享位置参数的唯一方法。
这是一个非常清晰的例子,这个答案需要更多人的支持。
@Elephant 不,子解析器的操作是互斥的。首先运行--verbose create -p 2
,然后运行--verbose update -p 3
【参考方案3】:
您还可以遍历子解析器并为所有子解析器添加相同的选项。
parser = argparse.ArgumentParser(prog="myProg")
subparsers = parser.add_subparsers(title="actions")
parser.add_argument("-v", "--verbose",
action="store_true",
dest="VERBOSE",
help="run in verbose mode")
parser_create = subparsers.add_parser ("create",
help = "create the orbix environment")
parser_update = subparsers.add_parser ("update",
help = "update the orbix environment")
for subparser in [parser_create, parser_update]:
subparser.add_argument ("-p",
type = int,
required = True,
help = "set db parameter")
【讨论】:
我认为这是一个不好的方法,因为您需要循环参数。 Sven Marnach 的答案更加干燥和可红色。【参考方案4】:您可以通过以下方式循环您的子解析器。
for name, subp in subparsers.choices.items():
print(subp)
subp.add_argument(dest='g', help='Input for g variable', default=7, type=int)
请注意,使用 subparsers.choices
可以避免对所有子解析器进行硬编码。
【讨论】:
这和@JanK的回答一样 @craymichael 不完全是。类似的,我给你。不同之处在于可迭代。 JanK 的答案使用解析器列表,我的使用 subparsers.choices.items()。 subparsers.choices.items() 的优点是 subparsers.choices.items() 总是包含所有使用的子解析器。使用列表时,您必须在添加或删除子解析器时更改它。我必须感谢 Jank 的想法,我只是更进一步,因为我不喜欢硬编码和维护列表。 @Gerald Kool 啊,我明白了。我在查看这个答案时错过了这一点!谢谢 这适用于 1 级解析器,但如果您有一个深度嵌套的命令树,递归地抓取子解析器可能会很困难。我在这里创建了一些辅助函数来简化此操作:github.com/turtlemonvh/argparse-subparser-filter 我喜欢这个,因为我可以在结尾写--verbose
,而不是开头以上是关于Python argparse - 向多个子解析器添加参数的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Python 3 中的现有程序创建带有 argparse 的子解析器?