Argparse - 不要用 `nargs` 捕获位置参数. [英] Argparse - do not catch positional arguments with `nargs`.

查看:24
本文介绍了Argparse - 不要用 `nargs` 捕获位置参数.的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to write a function wo which you can parse a variable amount of arguments via argparse - I know I can do this via nargs="+". Sadly, the way argparse help works (and the way people generally write arguments in the CLI) puts the positional arguments last. This leads to my positional argument being caught as part of the optional arguments.

#!/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 运行显示以下使用说明:

running this as ./test.py -h shows the following usage instruction:

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

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

but if I run ./test.py -o 0.21 0.11 0.33 0.13 100 gives me

test.py: error: too few arguments

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

to get a correct parsing of args, I have to run ./test.py 100 -o 0.21 0.11 0.33 0.13

那我该怎么办:

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

  • make argparse reformat the usage output so that it is less misleading, OR, even better:

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

tell argparse to not catch the last element for the optional argument -o if it is the last in the list

?

推荐答案

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

There is a bug report on this: http://bugs.python.org/issue9338

带有 nargs='?'、'*' 或 '+' 的 argparse 选项后面不能跟位置

argparse optionals with nargs='?', '*' or '+' can't be followed by positionals

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

A simple (user) fix is to use -- to separate postionals from optionals:

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

我写了一个补丁,保留了一些供位置使用的参数.但这不是一件小事.

I wrote a patch that reserves some of the arguments for use by the positional. But it isn't a trivial one.

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

As for changing the usage line - the simplest thing is to write your own, e.g.:

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

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

I wouldn't recommend adding logic to the usage formatter to make this sort of change. I think it would get too complex.

另一个快速解决方法是将此位置转换为(必需的)可选.它为用户提供了关于他们的订单的完全自由,并可能减少混淆.如果您不想混淆必需的可选",只需给它一个逻辑默认值即可.

Another quick fix is to turn this positional into an (required) optional. It gives the user complete freedom regarding their order, and might reduce confusion. If you don't want to confusion of a 'required optional' just give it a logical default.

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

<小时>

Help_Formatter 的一个简单更改是简单地按照定义的顺序列出参数.修改格式化程序行为的正常方法是对其进行子类化,并更改一两个方法.这些方法中的大多数都是私有的"(_ 前缀),因此您要意识到未来的代码可能会(缓慢地)更改.


One easy change to the Help_Formatter is to simply list the arguments in the order that they are defined. The normal way of modifying formatter behavior is to subclass it, and change one or two methods. Most of these methods are 'private' (_ prefix), so you do so with the realization that future code might change (slowly).

在此方法中,actions 是参数列表,按照定义的顺序排列.默认行为是将 'options' 从 'positionals' 中分离出来,并在最后用 positionals 重新组合列表.还有一些额外的代码可以处理需要换行的长行.通常它会将位置放在单独的行上.我已经省略了.

In this method, actions is the list of arguments, in the order in which they were defined. The default behavior is to split 'optionals' from 'positionals', and reassemble the list with positionals at the end. There's additional code that handles long lines that need wrapping. Normally it puts positionals on a separate line. I've omitted that.

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 ...]]

这篇关于Argparse - 不要用 `nargs` 捕获位置参数.的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆