Python argparse-向多个子解析器添加参数

我的脚本定义了一个主解析器和多个子解析器。我想将 -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

55053 次浏览

This can be achieved by defining a parent parser containing the common option(s):

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")

This produces help messages of the format:

parent_parser.print_help()

Output:

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()

Output:

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

However, if you run your program, you will not encounter an error if you do not specify an action (i.e. create or update). If you desire this behavior, modify your code as follows.

<...>
subparsers = parent_parser.add_subparsers(title="actions")
subparsers.required = True
subparsers.dest = 'command'
<...>

This fix was brought up in this SO question which refers to an issue tracking a pull request.

update by @hpaulj

Due to changes in handling subparsers since 2011, it is a bad idea to use the main parser as a parent. More generally, don't try to define the same argument (same dest) in both main and sub parsers. The subparser values will overwrite anything set by the main (even the subparser default does this). Create separate parser(s) to use as parents. And as shown in the documentation, parents should use add_help=False.

You can also loop over the subparsers and add the same option to all of them.

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")

You can loop over your subparsers in the following way.

for name, subp in subparsers.choices.items():
print(subp)
subp.add_argument(dest='g', help='Input for g variable', default=7, type=int)

Note that by using subparsers.choices that you avoid needing to hard-code all of the subparsers.

The accepted answer is correct; the proper way is to use parent parsers. However, the example code IMO was not really solving the problem. Let me add my few cents to provide a more suitable example.

The main difference with accepted answer is the explicit possibility to have some root-level arguments (like --verbose) as well as shared arguments only for some subparsers (-p only for the create and update subparsers but not for others)

# 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

This is the top-level help message (note that -p parameter is not shown here, which is exactly what you would expect—because it is specific to some subparsers):

>>> 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

And the help message for the create action:

>>> parser_create.print_help()
usage:  create [-h] -p P


optional arguments:
-h, --help  show this help message and exit
-p P        add db parameter