Python argparse 互斥组

我需要的是:

pro [-a xxx | [-b yyy -c zzz]]

我试过了,但是没有用。有人能帮帮我吗?

group= parser.add_argument_group('Model 2')
group_ex = group.add_mutually_exclusive_group()
group_ex.add_argument("-a", type=str, action = "store", default = "", help="test")
group_ex_2 = group_ex.add_argument_group("option 2")
group_ex_2.add_argument("-b", type=str, action = "store", default = "", help="test")
group_ex_2.add_argument("-c", type=str, action = "store", default = "", help="test")

谢谢!

72404 次浏览

add_mutually_exclusive_group不会使整个组互相排斥,而是使组内的选项互相排斥。

你需要的是 子命令,而不是 prog [-a xxxx | [-b yyy-c zzz ] ,你需要:

prog
command 1
-a: ...
command 2
-b: ...
-c: ...

用第一组参数调用:

prog command_1 -a xxxx

To invoke with the second set of arguments:

prog command_2 -b yyyy -c zzzz

还可以将子命令参数设置为位置参数。

prog command_1 xxxx

有点像 git 或 svn:

git commit -am
git merge develop

工作范例

# create the top-level parser
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--foo', action='store_true', help='help for foo arg.')
subparsers = parser.add_subparsers(help='help for subcommand', dest="subcommand")


# create the parser for the "command_1" command
parser_a = subparsers.add_parser('command_1', help='command_1 help')
parser_a.add_argument('a', type=str, help='help for bar, positional')


# create the parser for the "command_2" command
parser_b = subparsers.add_parser('command_2', help='help for command_2')
parser_b.add_argument('-b', type=str, help='help for b')
parser_b.add_argument('-c', type=str, action='store', default='', help='test')

测试一下

>>> parser.print_help()
usage: PROG [-h] [--foo] {command_1,command_2} ...


positional arguments:
{command_1,command_2}
help for subcommand
command_1           command_1 help
command_2           help for command_2


optional arguments:
-h, --help            show this help message and exit
--foo                 help for foo arg.
>>>


>>> parser.parse_args(['command_1', 'working'])
Namespace(subcommand='command_1', a='working', foo=False)
>>> parser.parse_args(['command_1', 'wellness', '-b x'])
usage: PROG [-h] [--foo] {command_1,command_2} ...
PROG: error: unrecognized arguments: -b x

祝你好运。

There is a python patch (in development) that would allow you to do this.
Http://bugs.python.org/issue10984

这个想法是允许重叠的相互排斥的组。因此,usage可能看起来像:

pro [-a xxx | -b yyy] [-a xxx | -c zzz]

更改 argparse 代码以便您可以像这样创建两个组是容易的部分。更改 usage格式化代码需要编写自定义 HelpFormatter

argparse中,操作组不影响解析。它们只是一个 help格式化工具。在 help中,相互排斥的组仅影响 usage行。在解析时,parser使用相互排斥的组构造一个潜在冲突的字典(a不能与 bc一起发生,b不能与 a一起发生等) ,然后在发生冲突时提出一个错误。

如果没有这个 argparse 补丁,我认为最好的选择是自己测试由 parse_args生成的名称空间(例如,如果 ab都有非默认值) ,并提出自己的错误。您甚至可以使用解析器自己的错误机制。

parser.error('custom error message')

While 乔纳森的回答 is perfectly fine for complex options, there is a very simple solution which will work for the simple cases, e.g. 1 option excludes 2 other options like in

command [- a xxx | [ -b yyy | -c zzz ]]

or even as in the original question:

pro [-a xxx | [-b yyy -c zzz]]

我会这么做:

parser = argparse.ArgumentParser()


# group 1
parser.add_argument("-q", "--query", help="query")
parser.add_argument("-f", "--fields", help="field names")


# group 2
parser.add_argument("-a", "--aggregation", help="aggregation")

我在这里使用给命令行包装器的选项来查询 mongodb。collection实例可以使用可选参数 queryfields调用方法 aggregate或方法 find,因此您可以看到为什么前两个参数是兼容的,而最后一个参数是不兼容的。

所以现在我运行 parser.parse_args()并检查它的内容:

args = parser.parse_args()


if args.aggregation and (args.query or args.fields):
print "-a and -q|-f are mutually exclusive ..."
sys.exit(2)

当然,这个小技巧只适用于简单的情况,如果您有许多相互排斥的选项和组,那么检查所有可能的选项将成为一场噩梦。在这种情况下,您应该像 Jonathan 建议的那样,将选项划分为命令组。

如果您不希望使用子解析器,那么目前可以使用相互排斥的组来完成,但是公平地警告,它涉及到访问私有变量,因此使用它的风险由您自己承担。这个想法是你希望 -a-b-c相互排斥,但是 -b-c不希望彼此相互排斥

import argparse
p = argparse.ArgumentParser()


# first set up a mutually exclusive group for a and b
g1 = p.add_mutually_exclusive_group()
arg_a = g1.add_argument('-a')  # save this _StoreAction for later
g1.add_argument('-b')


# now set up a second group for a and c
g2 = p.add_mutually_exclusive_group()
g2.add_argument('-c')
g2._group_actions.append(arg_a)  # this is the magic/hack

现在我们有 -a独家的 -c-b

a = p.parse_args(['-a', '1'])
# a.a = 1, a.b = None, a.c = None


a = p.parse_args(['-a', '1', '-b', '2'])
# usage: prog.py [-h] [-a A | -b B] [-c C]
# prog.py: error: argument -b: not allowed with argument -a

注意,它的确会把帮助消息搞乱,但是您可以覆盖它,或者只是忽略它,因为您已经得到了所需的功能,无论如何,这可能更重要。

如果您想确保是否使用了 b 和 c 中的任何一个,则必须同时使用它们,那么在实例化相互排斥的组时,只需添加 required=True关键字 arg。