允许 argparse nargs="+" 接受带有选项的逗号分隔输入

Allow argparse nargs="+" to accept comma-separated input with choices

我想使用 argparse 的 {choices} 参数,但允许用户从选项中输入任意数量的项目。例如,如果选择是 [1,2,3],我希望以下内容有效:

--arg 1
--arg 1,2
--arg 1,3

等等

但是,使用 nargs="+" 时,选择似乎不接受以逗号分隔的输入。有没有办法解决?我仍然想强制传入的选项在我定义的选项集中,以对奇怪的输入进行错误检查。

这一行代码为您提供了所有可能的选择子集。

    from itertools import combinations, chain
    allsubsets = lambda n: list(chain(*[combinations(range(n), ni) for ni in range(n+1)]))

我同意 - 你会认为 API 会允许现在有人这样做吗?

无论如何,我一直使用的解决方法如下:

p = argparse.ArgumentParser(description="Why doesn't argparse support list of args?")
parser.add_argument('--arg', type=str)
arg_list = parser.parse_args().args.split(",")
# if you wanted integers:
arg_list = [int(x) for x in arg_list]

又名:接收字符串并自行处理。

import argparse, sys
print(sys.argv)
parser = argparse.ArgumentParser()
parser.add_argument('--arg', nargs='+', choices=[1,2,3], type=int)
args = parser.parse_args()
print(args)

一些跑步

1455:~/mypy$ python stack49824248.py --arg 1 
['stack49824248.py', '--arg', '1']
Namespace(arg=[1])

1455:~/mypy$ python stack49824248.py --arg 1 3 2 1
['stack49824248.py', '--arg', '1', '3', '2', '1']
Namespace(arg=[1, 3, 2, 1])

1456:~/mypy$ python stack49824248.py --arg 1,2
['stack49824248.py', '--arg', '1,2']
usage: stack49824248.py [-h] [--arg {1,2,3} [{1,2,3} ...]]
stack49824248.py: error: argument --arg: invalid int value: '1,2'

shell 与解释器一起将输入拆分为空格,并在 sys.argv 中提供字符串列表。这就是 parser 处理的内容。

对于 +--arg 操作接受字符串列表(到末尾或下一个标志)。每个字符串都通过 type 函数传递,并将结果与​​ choices(如果提供)进行比较。在这种情况下,typeint,因此选项也可以是整数。如果没有 typechoices 就必须是 ['1','2','3']

如果我将参数更改为:

parser.add_argument('--arg', nargs='+', choices=['1','2','3','1,2','2,3'])

它将接受一些带逗号的字符串:

1456:~/mypy$ python stack49824248.py --arg 1
['stack49824248.py', '--arg', '1']
Namespace(arg=['1'])
1505:~/mypy$ python stack49824248.py --arg 1,2
['stack49824248.py', '--arg', '1,2']
Namespace(arg=['1,2'])
1505:~/mypy$ python stack49824248.py --arg 1,2,3
['stack49824248.py', '--arg', '1,2,3']
usage: stack49824248.py [-h] [--arg {1,2,3,1,2,2,3} [{1,2,3,1,2,2,3} ...]]
stack49824248.py: error: argument --arg: invalid choice: '1,2,3' (choose from '1', '2', '3', '1,2', '2,3')

我没有包括“1,2,3”选项,所以它拒绝了。另请注意,我删除了 int type,因为 int('1,2') 会失败。

因此,如果您需要接受“1,2,3”,请在解析后进行自己的拆分和选择测试(或者可能作为自定义 Action class)。

In [16]: [(int(x) in [1,2,3]) for x in '1,2,3'.split(',')]
Out[16]: [True, True, True]
In [17]: [(int(x) in [1,2,3]) for x in '1,2,4'.split(',')]
Out[17]: [True, True, False]
In [18]: [(int(x) in [1,2,3]) for x in '1,a,4'.split(',')]
....
ValueError: invalid literal for int() with base 10: 'a'