如何在 argparse 中使用带有 nargs='*' 参数的可选位置参数?

Posted

技术标签:

【中文标题】如何在 argparse 中使用带有 nargs=\'*\' 参数的可选位置参数?【英文标题】:How to use optional positional arguments with nargs='*' arguments in argparse?如何在 argparse 中使用带有 nargs='*' 参数的可选位置参数? 【发布时间】:2017-02-23 07:13:59 【问题描述】:

如下代码所示,我想有一个可选的位置参数files,我想为它指定一个默认值,当传入路径时,使用指定路径。

但是因为--bar可以有多个参数,所以传入的路径没有进入args.files,我该如何解决呢?谢谢!

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
parser.add_argument('--bar', nargs='*')
parser.add_argument('files', nargs='?')

cmd = '--foo a --bar b c d '
print parser.parse_args(cmd.split())
# Namespace(bar=['b', 'c', 'd'], files=None, foo='a')


cmd = '--foo a --bar b c d /path/to/file1'
print parser.parse_args(cmd.split())
# Namespace(bar=['b', 'c', 'd', '/path/to/file1'], files=None, foo='a')

【问题讨论】:

argparse 怎么知道/path/to/file1files 而不是bar 【参考方案1】:

您的参数规范本质上是模棱两可的(因为--bar 可以接受无限参数,所以没有好的方法来判断它何时结束,特别是因为files 是可选的),所以它需要用户消歧。具体来说,argparse 可以通过将-- 放在仅位置部分之前来告知“这是开关部分的结尾,所有后续参数都是位置的”。如果你这样做:

cmd = '--foo a --bar b c d -- /path/to/file1'
print parser.parse_args(cmd.split())

你应该得到:

Namespace(bar=['b', 'c', 'd'], files='/path/to/file1', foo='a')

(在 Py3 上测试,但也应该适用于 Py2)

或者,用户可以通过避免将位置参数放在--bar 之后,将位置参数传递到任何明确的位置,例如:

cmd = '/path/to/file1 --foo a --bar b c d'

cmd = '--foo a /path/to/file1 --bar b c d'

最后,你可以避免使用nargs='*' 作为开关,因为它引入了歧义。相反,将--bar 定义为多次接受,每个开关使用一个值,将所有使用累积到list

parser.add_argument('--bar', action='append')

然后你传递--bar 多次以一次提供多个值,而不是一次传递多个值:

cmd = '--foo a --bar b --bar c --bar d /path/to/file1'

【讨论】:

以上是关于如何在 argparse 中使用带有 nargs='*' 参数的可选位置参数?的主要内容,如果未能解决你的问题,请参考以下文章

argparse 错误: 'nargs 必须是 %r 才能提供 const' % OPTIONAL)

具有 nargs 行为的 Python argparse 不正确

如何使 argparse 将所有参数视为位置?

帮助文本中的 Python argparse 参数顺序

用 argparse 杀死解释器

argparse模块见解