使用nargs =' +'解析Python subparser

时间:2016-03-09 17:50:09

标签: python argparse

我必须用这样的命令行参数创建一个解析器

python function.py -v 1 name1 -d abc xyz foo bar name2 -i 3 -p abc xyz

我这样做了:

import argparse
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('-v', type=int, help='number')

subparsers = parser.add_subparsers(help='sub-command help', dest="command")
parser_a = subparsers.add_parser('name1', help="name1 help")
parser_a.add_argument("-d", help="list", nargs="+")

parser_b = subparsers.add_parser('name2', help="name2 help")
parser_b.add_argument("-p", help="list2", nargs='+')
parser_b.add_argument("-i", help="number inside name2", type=int)

当我运行时:

parser.parse_args('-v 1 name1 -d abc xyz foo bar name2 -i 3 -p abc xyz'.split())

结果是:

usage: PROG [-h] [-v V] {name1,name2} ...
PROG: error: unrecognized arguments: -i 3 -p abc xyz

运行时:

parser.parse_args('-v 1 name1 -d abc xyz foo bar name2'.split())

结果如下:

Namespace(command='name1', d=['abc', 'xyz', 'foo', 'bar', 'name2'], v=1)

我希望它是这样的:

Namespace(command='name1', d=['abc', 'xyz', 'foo', 'bar'], command='name2', p=['abc', 'xyz'], i=3, v=1)

我该怎么做?

2 个答案:

答案 0 :(得分:0)

当你注意到

In [24]: parser.parse_args('-v 1 name1 -d abc xyz foo bar name2'.split())
Out[24]: Namespace(command='name1', d=['abc', 'xyz', 'foo', 'bar', 'name2'], v=1)

name2被视为parser_a -d参数

的参数之一

其他'-i 3 -p abc xyz'不被接受,因为-i被理解为可选标志。

有效地你正在运行:

In [28]: parser_a.parse_args('-d abc xyz foo bar name3 -i 3 -p abc xyz'.split())
usage: PROG name1 [-h] [-d D [D ...]]
PROG name1: error: unrecognized arguments: -i 3 -p abc xyz

主解析器有一个位置参数,可接受2个选项,name1name2。当遇到name1时,它会将其余参数传递给parser_a

净效果是argparse只接受一个子命令。

在之前的SO问题中,我已经讨论了一些方法。侧边栏找到了一个:

Python argparser repeat subparse

(这可能足以将此问题标记为重复)。

如果我向parser_a添加位置;并使用--分隔barname2(意思是,以下所有内容都是位置)

In [32]: parser_a.add_argument('extra',nargs='*')
Out[32]: _StoreAction(option_strings=[], dest='extra', nargs='*', const=None, default=None, type=None, choices=None, help=None, metavar=None)

In [33]: parser.parse_args('-v 1 name1 -d abc xyz foo bar -- name2 -i 3 -p abc xyz'.split())
Out[33]: Namespace(command='name1', d=['abc', 'xyz', 'foo', 'bar'], extra=['name2', '-i', '3', '-p', 'abc', 'xyz'], v=1)

然后我可以将extra字符串(减去name2)传递给parser_b

In [34]: args=_
In [36]: parser_b.parse_args(args.extra[1:])
Out[36]: Namespace(i=3, p=['abc', 'xyz'])

不可否认,这是一个令人费解的解决方案,但几年前我提出的解决方案并没有好多少。希望它有助于澄清正在发生的事情。

您是否真的需要一次调用2个子命令。如果可以的话,argparse会更简单:

python function.py -v 1 name1 -d abc xyz foo bar
python function.py -v 1 name2 -i 3 -p abc xyz

换句话说,调用脚本两次。如果对function.py的每次调用都执行独立的自包含操作,那么这很容易 - 在共享文件或数据库中包含的两个调用之间存在任何连接。这就是经常使用子命令的方式。尝试在一次调用中放置多个子命令不会节省输入。

答案 1 :(得分:0)

我认为你做错了什么。 首先,您应该传递位置参数,然后传递关键字参数,例如

python myapp.py arg1 arg2 --kwarg1=1 --kwarg2 val1 --kwarg2 val2