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中观察到了这种行为。
答案 0 :(得分:1)
相关代码隐藏在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 the sense that an empty list satisfies its
nargs . In that case it gets the
action.default value. That's handled by a special case in
_ get_values()`。
但是对于互斥测试我们不希望这些行为被“看到”,因此这个额外的测试来设置'seen_non_default_actions`集。
is
测试非常严格。这些项目必须具有相同的id
。
您的示例失败,因为True
中的const=True
具有与default=True
中相同的ID。
parser.parse_args(['--foo', '--bar'])
将foo
设置为const
。但是因为它与default
匹配,所以它不会被看到,并且不会触发排他错误。
通常const
和default
会有不同的值,利用'?'的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