Argparse - 不要用'nargs`捕获位置参数。

时间:2014-11-18 02:36:35

标签: python argparse argument-passing

我正在尝试编写一个函数wo,您可以通过argparse解析可变数量的参数 - 我知道我可以通过nargs="+"执行此操作。遗憾的是,argparse帮助的工作方式(以及人们通常在CLI中编写参数的方式)将位置参数放在最后。这导致我的位置参数被捕获为可选参数的一部分。

#!/usr/bin/python
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("positional", help="my positional arg", type=int)
parser.add_argument("-o", "--optional", help="my optional arg", nargs='+', type=float)
args = parser.parse_args()
print args.positional, args.optional

./test.py -h运行此操作会显示以下使用说明:

usage: test.py [-h] [-o OPTIONAL [OPTIONAL ...]] positional

但如果我跑./test.py -o 0.21 0.11 0.33 0.13 100给我

test.py: error: too few arguments

要正确解析args,我必须运行./test.py 100 -o 0.21 0.11 0.33 0.13

那我该如何:

  • 让argparse重新格式化使用输出,以免误导,或者甚至更好:

  • 告诉argparse没有捕获可选参数-o的最后一个元素,如果它是列表中的最后一个

2 个答案:

答案 0 :(得分:16)

有关于此的错误报告:http://bugs.python.org/issue9338

  

argparse选项与nargs ='?',' *'或' +'不能跟随位置

一个简单的(用户)修复方法是使用--将postionals与期权分开:

./test.py -o 0.21 0.11 0.33 0.13 -- 100

我写了一个补丁,保留了位置使用的一些参数。但这不是一件微不足道的事。

至于更改使用线 - 最简单的方法是自己编写,例如:

usage: test.py [-h] positional [-o OPTIONAL [OPTIONAL ...]]
usage: test.py [-h] [-o OPTIONAL [OPTIONAL ...]] -- positional

我不建议在使用格式化程序中添加逻辑以进行此类更改。我认为这会变得太复杂。

另一个快速解决方法是将此位置转换为(必需)可选项。它为用户提供了完全自由的订单,可以减少混淆。如果您不想混淆所需的选项'只是给它一个逻辑默认值。

usage: test.py [-h] [-o OPTIONAL [OPTIONAL ...]] -p POSITIONAL
usage: test.py [-h] [-o OPTIONAL [OPTIONAL ...]] [-p POS_WITH_DEFAULT]

对Help_Formatter的一个简单更改是简单地按照定义的顺序列出参数。修改格式化程序行为的常规方法是将其子类化,并更改一个或两个方法。这些方法中的大多数都是私人的' (_前缀),所以你要意识到未来的代码可能会改变(慢慢地)。

在此方法中,actions是参数列表,按其定义的顺序排列。默认行为是拆分'选项'来自' positionals',并在结尾处使用位置重新组合列表。还有其他代码可以处理需要换行的长行。通常它会将位置放在一个单独的行上。我已经省略了。

class Formatter(argparse.HelpFormatter):
    # use defined argument order to display usage
    def _format_usage(self, usage, actions, groups, prefix):
        if prefix is None:
            prefix = 'usage: '

        # if usage is specified, use that
        if usage is not None:
            usage = usage % dict(prog=self._prog)

        # if no optionals or positionals are available, usage is just prog
        elif usage is None and not actions:
            usage = '%(prog)s' % dict(prog=self._prog)
        elif usage is None:
            prog = '%(prog)s' % dict(prog=self._prog)
            # build full usage string
            action_usage = self._format_actions_usage(actions, groups) # NEW
            usage = ' '.join([s for s in [prog, action_usage] if s])
            # omit the long line wrapping code
        # prefix with 'usage:'
        return '%s%s\n\n' % (prefix, usage)

parser = argparse.ArgumentParser(formatter_class=Formatter) 

生成如下使用行:

usage: stack26985650.py [-h] positional [-o OPTIONAL [OPTIONAL ...]]

答案 1 :(得分:9)

请考虑使用nargs="+",而不是action="append"。这需要在每个数字前面传递-o,但除非你真的想要它,否则它不会消耗参数。