在 argparse 中,是否可能有来自多个父解析器的源互斥参数?

In argparse, is it possible to have source mutually exclusive args from multiple parent parsers?

下面将设置一个互斥组,其中“-a”或“-b”只有一个有效。

import argparse

parser = argparse.ArgumentParser()
group = parser.add_add_mutually_exclusive_group()
group.add_argument('-a')
group.add_argument('-b')

我想改为提供来自其他解析器的“-a”和“-b”参数。类似于:

a_parser = argparse.ArgumentParser()
a_parser.add_argument('-a')

b_parser = argparse.ArgumentParser()
b_parser.add_argument('-b')

parser = argparse.ArgumentParser()
group = parser.add_add_mutually_exclusive_group()
group.SOME_HOW_ADD_ARGS_FROM_OTHER_PARSER(a_parser)
group.SOME_HOW_ADD_ARGS_FROM_OTHER_PARSER(b_parser)

在这两种情况下,我希望以下内容会引发有关使用不兼容参数的异常:

parser.parse_args(['-a', '1', '-b', '1'])

问题是我不知道我缺少的“SOME_HOW_ADD_ARGS_FROM_OTHER_PARSER”逻辑是否存在。如果它确实存在,我不知道该怎么做。有人有什么想法吗?

是的,有一种方法,但它使用了解析器的一些隐藏属性。我正在使用为

开发的想法

http://bugs.python.org/issue10984 argparse add_mutually_exclusive_group should accept existing arguments to register conflicts

使用 add_help=False 创建 2 个 parent 解析器(以防止 -h 参数发生冲突 - 这是标准的 parent 解析器过程)

a_parser = argparse.ArgumentParser(add_help=False)
aaAction = a.parser.add_argument('-a')
b_parser = argparse.ArgumentParser(add_help=False)
bbAction = b_parser.add_argument('-b')

parser=argparse.ArgumentParser(parents=[a_parser, b_parser])
group=parser.add_mutually_exclusive_group()

此时parser有3个动作(参数),可以在一个'private'属性中看到,_actions:

print parser._actions
""" 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=['-a'], dest='a', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None),
 _StoreAction(option_strings=['-b'], dest='b', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]
"""

第一个是自己的help,其他都是从parent继承的。我之前还保存了指向这些 aaActionbbAction 的指针。现在我们只需要将这些添加到 group_group_actions 列表中:

group._group_actions.append(parser._actions[1]) # or (aaAction)
group._group_actions.append(parser._actions[2]) # or (bbAction)

如果补丁 10984 已经实施,我们可以写成:

group = parser.add_mutually_exclusive_group(aaAction, bbAction)

这将作为创建组的一部分执行此追加。

我们可以通过以下方式进行测试:

In [31]: print parser.format_help()
usage: ipython [-h] [-a A | -b B]

optional arguments:
  -h, --help  show this help message and exit
  -a A
  -b B


In [32]: parser.parse_args(['-a','a'])
Out[32]: Namespace(a='a', b=None)

In [33]: parser.parse_args(['-a','a','-b','b'])
usage: ipython [-h] [-a A | -b B]
ipython: error: argument -b: not allowed with argument -a
An exception has occurred, use %tb to see the full traceback.

这取决于几条信息:

  • add_argument returns 指向刚刚创建的 Action 的指针。

  • parents 通过仅复制动作点,即通过引用将动作添加到新解析器。

  • 知道 parsegroup 存储其相关操作列表的位置。

  • 了解将动作添加到组与将其添加到解析器有何不同(不多)。

我建议在交互式 shell(如 IPython)中测试这样的代码,您可以在其中查看 parsergroup 的属性。并随身携带一份 Lib/argparse.py。 :)

补丁 10984 添加了一些代码来处理在多个组中执行操作的复杂情况。通常一个动作只属于一个组。