Python argparse:将可选参数与nargs = argparse.REMAINDER组合在一起

时间:2013-09-04 20:03:07

标签: python argparse

我必须遗漏一些明显的东西。目标是使用argparse和第一个参数,第二个可选参数和任何其他剩余参数可选。

为了显示问题,我制作了两个测试解析器;它们之间的唯一区别是在一个中使用nargs = argparse.REMAINDER而在另一个中使用nargs ='*'。

def doParser1(argsin):
    parser = argparse.ArgumentParser(description='Parser demo.')
    parser.add_argument('req1', help='first required parameter')
    parser.add_argument('--opt1', help='first optional parameter')
    parser.add_argument('leftovers', nargs=argparse.REMAINDER,
                    help='all the other parameters')
    argsout = parser.parse_args(args=argsin)
    print argsout
    return argsout

def doParser2(argsin):
    parser = argparse.ArgumentParser(description='Parser demo.')
    parser.add_argument('req1', help='first required parameter')
    parser.add_argument('--opt1', help='first optional parameter')
    parser.add_argument('leftovers', nargs='*',
                    help='all the other parameters')
    argsout = parser.parse_args(args=argsin)
    print argsout
    return argsout

如果没有额外参数,则parser2可以正常工作。这是输入,后跟parser1和解析器1:

input: ['req1value', '--opt1', 'opt1value']
Namespace(leftovers=['--opt1', 'opt1value'], opt1=None, req1='req1value')
Namespace(leftovers=None, opt1='opt1value', req1='req1value')

如果有额外的参数,则在parser1中会遗漏opt1值,而解析器2会混淆:

input: ['req1value', '--opt1', 'opt1value', 'r1', 'r2']
Namespace(leftovers=['--opt1', 'opt1value', 'r1', 'r2'], opt1=None, req1='req1value')
usage: py-argparse.py [-h] [--opt1 OPT1]
                  [-leftovers [LEFTOVERS [LEFTOVERS ...]]]
                  req1
py-argparse.py: error: unrecognized arguments: r1 r2

预期输出应为:

Namespace(leftovers=['r1', 'r2'], opt1='opt1value', req1='req1value')

这似乎应该是一个简单的案例,这里的内容从我真正想要做的事情中简化了。我尝试过剩饭是可选的,添加了各种其他选项,但没有任何效果更好。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:4)

--opt1需要在“未命名”参数之前出现。你真正的测试用例应该是:

    ['--opt1', 'opt1value', 'req1value']

    ['--opt1', 'opt1value', 'req1value', 'r1', 'r2']

答案 1 :(得分:4)

您可以使用parse_known_args

import argparse
parser = argparse.ArgumentParser(description='Parser demo.')
parser.add_argument('req1', help='first required parameter')
parser.add_argument('--opt1', help='first optional parameter')

args, leftovers = parser.parse_known_args(['req1value', '--opt1', 'opt1value'])
print(args, leftovers)
# (Namespace(opt1='opt1value', req1='req1value'), [])

args, leftovers = parser.parse_known_args(['req1value', '--opt1', 'opt1value', 'r1', 'r2'])
print(args, leftovers)
# (Namespace(opt1='opt1value', req1='req1value'), ['r1', 'r2'])

答案 2 :(得分:2)

当一个或多个位置属于“零或更多”类型(? * REMAINDER)时,位置和选项的混合是棘手的。简单的解决方案是不混合它们 - 首先给出选项,然后是所有的位置。

这是发生了什么:

input: ['req1value', '--opt1', 'opt1value']
Namespace(leftovers=['--opt1', 'opt1value'], opt1=None, req1='req1value')

由于req1value字符串,解析器首先解析位置。 req1想要1个字符串,leftovers抓取其他所有内容,包括--opt1

Namespace(leftovers=None, opt1='opt1value', req1='req1value')

* leftovers[]感到满意,没有字符串,因此None(实际上我得到[])。 --opt1被解析为可选项。

input: ['req1value', '--opt1', 'opt1value', 'r1', 'r2']
...
py-argparse.py: error: unrecognized arguments: r1 r2

之前* leftovers设置为[]-opt1已处理完毕。但现在有2个字符串没有放置它们的地方。你打算让他们进入leftovers,但那已经被使用了。如果leftovers+,则会按照您的意图对其进行处理。

关键是当它试图解析第一个位置时,它也会尝试解析它可以的所有位置。在一个级别parse_args正在生成re.match('(A)(A*)','AOA')('A', '')

有2个提议的补丁可以解决这个问题。一个人使用2步parse_known_args来完成选项和位置的混合。这是optparse用户可能期望的那种行为。

另一个补丁尝试延迟处理可以接受0参数字符串http://bugs.python.org/issue15112的位置。