参数解析器:使用某些参数选项时不强制执行的独占组


import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('--foo', nargs='?', default=True, const=True)
group.add_argument('--bar', dest='foo', action='store_false')
parser.parse_args(['--foo', '--bar']) # no error

我有点困惑,尽管--foo--bar应该是排他性的,但上面的代码不会产生任何错误。这是预期的行为吗?还是我们不应该在排他性组中弄乱参数选项?

请注意,当default=True未作为参数传递给--foo时,会发生预期的错误。

我在Python 2.7.13和3.5.3中观察到了这种行为。

相关代码隐藏在take_action

argument_values = self._get_values(action, argument_strings)
# error if this argument is not allowed with other previously
# seen arguments, assuming that actions that use the default
# value don't really count as "present"
if argument_values is not action.default:
seen_non_default_actions.add(action)
for conflict_action in action_conflicts.get(action, []):
if conflict_action in seen_non_default_actions:
msg = _('not allowed with argument %s')
action_name = _get_action_name(conflict_action)
raise ArgumentError(action, msg % action_name)

具体来说,'argument_values is not action.default'测试。

可选位置(nargs='?')总是"在操作. In that case it gets the, in the sense that an empty list satisfies itsnargs看到"。默认value. That's handled by a special case in_get_values()"。

但是对于互斥测试,我们不希望这些动作被"看到",因此这个额外的测试来设置"seen_non_default_actions"集。

is测试非常严格。 这些项目必须具有相同的id

您的示例失败,因为const=True中的Truedefault=True中的 id 相同。

parser.parse_args(['--foo', '--bar'])设置fooconst。 但由于它与default匹配,因此不可见,并且不会触发排他性错误。

通常,constdefault将具有不同的值,利用 '?' 的 3 向解析。

is not测试在另一种情况下失败。 小于 256 的数字是唯一的。 更多关于这方面的内容,请访问 http://bugs.python.org/issue18943


测试用例:

In [1]: import argparse
...: parser = argparse.ArgumentParser()
...: group = parser.add_mutually_exclusive_group()
...: a1=group.add_argument('--foo', nargs='?', default=True, const=True)
...: a2=group.add_argument('--bar', action='store_false')
...: 
In [2]: parser.parse_args(['--foo', '--bar'])
Out[2]: Namespace(bar=False, foo=True)      # the True's match

更改const

In [3]: a1.const
Out[3]: True
In [4]: a1.const='other'
In [5]: parser.parse_args(['--foo', '--bar'])
usage: ipython3 [-h] [--foo [FOO] | --bar]
ipython3: error: argument --bar: not allowed with argument --foo
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2

值在is意义上匹配的另一种情况:

In [6]: a1.const=None;a1.default=None
In [7]: parser.parse_args(['--foo', '--bar'])
Out[7]: Namespace(bar=False, foo=None)

对于少量数字:

In [8]: a1.const=3;a1.default=3
In [9]: parser.parse_args(['--foo', '--bar'])
Out[9]: Namespace(bar=False, foo=3)

但不是大的:

In [10]: a1.const=300;a1.default=300
In [11]: parser.parse_args(['--foo', '--bar'])
usage: ipython3 [-h] [--foo [FOO] | --bar]
ipython3: error: argument --bar: not allowed with argument --foo
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2

字符串可能很棘手。 代码中的文本是唯一的,但通过拆分创建的文本不是:

In [12]: a1.default='test'
In [14]: parser.parse_args(['--foo', 'test', '--bar'])
Out[14]: Namespace(bar=False, foo='test')   # no error

这更像是命令行提供字符串的方式:

In [16]: parser.parse_args('--foo test --bar'.split())
usage: ipython3 [-h] [--foo [FOO] | --bar]
ipython3: error: argument --bar: not allowed with argument --foo
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2

最新更新