【发布时间】:2021-12-13 11:38:07
【问题描述】:
我使用argparse 来获取使用choices 和nargs='*' 的元素子集。如果没有引入任何元素,我想默认返回元素的一个子集,但我得到一个Invalid Choice 错误。
这是我的示例代码:
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument(
"choices",
nargs="*",
type=int,
choices=[1,2,3,4,5],
default=[1,3,5]
)
if __name__ == "__main__":
print(parser.parse_args().choices)
我得到的输出是:
$ ./thing.py 3
[3]
$ ./thing.py 1 2
[1, 2]
$ ./thing.py
usage: thing.py [-h] [{1,2,3,4,5} ...]
thing.py: error: argument choices: invalid choice: [1, 3, 5] (choose from 1, 2, 3, 4, 5)
我可以将默认值设置为 int,但不能设置为列表。有什么解决方法吗?
编辑:这似乎只发生在位置参数上。如果在非位置参数中使用 nargs="+" 和 required=False 不会有任何问题。
【问题讨论】:
-
我最终放弃了使用位置参数,它降低了 CLI 的可读性。我会留下这个问题,以防有人遇到同样的问题并想解决它。
-
这是一个非常有趣的问题,几乎感觉像是一个错误。我试图开始调查(通过源代码),但现在还没有充分的时间。据我所知,如果您实际传递参数,它们将按以下顺序逐个执行:首先根据
type进行转换,然后检查它们是否在choices中,然后附加到列表中(因为nargs) .使用默认值的时候,好像是直接保存到Namespace,然后签入choices会失败... -
因为
*满足一个空列表,所以它的default得到特殊处理。检查_get_values子方法。这包括选择测试,非字符串默认值通常会绕过。 @Tomerikoo -
@hpaulj 感谢您的回复。不确定我是否完全理解,但我确实在docs 中看到“如果默认值是字符串,则解析器会解析该值,就好像它是命令行参数一样。特别是,解析器应用任何类型转换参数(如果提供),然后在命名空间返回值上设置属性。否则,解析器将按原样使用该值“但是当我尝试这样做时(
default="1")我仍然得到invalid choice: '1' (choose from 1, 2, 3, 4, 5) -
@Tomerikoo,我在答案中详细说明了这种对默认值的处理。