11

我一定遗漏了一些明显的东西。目标是使用 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 工作。这是解析器 1 和解析器 1 后跟的输入:

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

如果有额外的参数,则在 parser1 中缺少 opt1 值,并且 parser2 只会混淆:

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')

看来这应该是一个简单的案例,这里的内容是我真正想做的事情的简化。我尝试过让剩菜可选,添加各种其他选项,但没有比这更好的了。

任何帮助,将不胜感激。

4

3 回答 3

5

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

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

    ['--opt1', 'opt1value', 'req1value', 'r1', 'r2']
于 2013-09-04T20:17:19.113 回答
5

你可以使用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'])
于 2013-09-04T20:34:55.323 回答
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')

With* 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的位置。

于 2013-09-05T20:33:19.997 回答