5

我正在使用 pythons(2.7.2) argparse (1.1) 来解析命令行,我想要的是创建 subparser 并使多次输入 subparser 命令成为可能。像这样:

./script.py version 1 --file 1 2 3 version 3 --file 4 5 6

有可能创造出这样的东西吗?因为现在当我尝试在结果命名空间中运行带有此类参数的脚本时,得到:

Namespace(file=['4', '5', '6'], n=[1])

n 它是一个版本号。所以我得到了第一个版本号和第二个文件列表,而不是文件列表和版本。

4

1 回答 1

5

To the main parser, the subparsers argument is a positional that takes choices. But it also allocates ALL of the remaining argument strings to the subparser.

I expect that your string is parsed as follows:

./script.py version 1 --file 1 2 3 version 3 --file 4 5 6

version is accepted as a subparser name. 1 is accepted as value to positional argument n. (of the subparser). --file is accepted as a optional argument (by the subparser). The values from the second invocation overwrite the values from the first. I'm guessing --file has nargs='*'. If so, the first one writes ['1','2','3','version','3'] to the namespace, while the second overwrites it with ['4','5','6']. If nargs=3, I would expect the subparser to choke on the second version, which it would see as an unknown positional.

So the basic point is - once the 'version' subparser gets the argument list, it does not let go until it has parsed everything it can. In this case it parses both --file occurrences. Anything it can't handle comes back to the main parser as 'UNKNOWNS', which normally raises an error.


If you want values from repeated optionals, use an append action

parser.add_argument('--foo',action='append', nargs=3)

import argparse
parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='version')
spp = sp.add_parser('version')
spp.add_argument('n',nargs='*',type=int)
spp.add_argument('--file',nargs=3,action='append')
str = 'version 1 --file 1 2 3 version 3 --file 4 5 6'
print(parser.parse_known_args(str.split()))

produces

(Namespace(file=[['1', '2', '3'], ['4', '5', '6']], n=[1], version='version'), ['version', '3'])

Still only one call to version subparser, but all the data is present.


A different approach would be to nest subparsers

parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='sub')
spp = sp.add_parser('version')
spp.add_argument('n',nargs=1,type=int)
spp.add_argument('--file',nargs=3)

sp = spp.add_subparsers(dest='sub1')
spp = sp.add_parser('version')
spp.add_argument('n1',nargs=1,type=int)
spp.add_argument('--file',dest='file1',nargs=3)

str = 'version 1 --file 1 2 3 version 3 --file 4 5 6'
print(parser.parse_args(str.split()))

Note that I have to change the 'dest' to avoid over writing values. This produces

Namespace(file=['1', '2', '3'], file1=['4', '5', '6'], n=[1], n1=[3], sub='version', sub1='version')
于 2013-10-01T15:55:48.270 回答