Argparse:“可选参数”下列出的必需参数?

Posted

技术标签:

【中文标题】Argparse:“可选参数”下列出的必需参数?【英文标题】:Argparse: Required arguments listed under "optional arguments"? 【发布时间】:2014-08-02 13:11:36 【问题描述】:

我使用下面的简单代码来解析一些参数;请注意,其中之一是必需的。不幸的是,当用户在不提供参数的情况下运行脚本时,显示的用法/帮助文本并不表示存在非可选参数,我觉得这很混乱。如何让 python 表明一个参数不是可选的?

代码如下:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Foo')
    parser.add_argument('-i','--input', help='Input file name', required=True)
    parser.add_argument('-o','--output', help='Output file name', default="stdout")
    args = parser.parse_args()
    print ("Input file: %s" % args.input )
    print ("Output file: %s" % args.output )

在不提供所需参数的情况下运行上述代码时,我得到以下输出:

usage: foo.py [-h] -i INPUT [-o OUTPUT]

Foo

optional arguments:
    -h, --help            show this help message and exit
    -i INPUT, --input INPUT
                          Input file name
    -o OUTPUT, --output OUTPUT
                          Output file name

【问题讨论】:

在用法行中,-i INPUT 部分没有被方括号括起来,这微妙地表明确实是必需的。此外,您可以通过 help 参数手动解释这一点 @JaimeRGP 是的,但这还不够,当然,它也不够突出。为所需参数分配的组名optional arguments 仍然具有误导性。 【参考方案1】:

--- 开头的参数通常被认为是可选的。所有其他参数都是位置参数,因此设计需要(如位置函数参数)。可能需要可选参数,但这有点违背他们的设计。由于它们仍然是非位置参数的一部分,即使它们是必需的,它们仍将列在令人困惑的标题“可选参数”下。然而,用法部分中缺少的方括号表明它们确实是必需的。

另见documentation:

通常,argparse 模块假定 -f 和 --bar 等标志表示可选参数,在命令行中始终可以省略。

注意:必需选项通常被认为是错误的形式,因为用户希望选项是可选的,因此应尽可能避免使用。

话虽如此,帮助中的标题 “位置参数”“可选参数” 是由两个参数组生成的,其中的参数自动分成。现在,您可以“破解它”并更改可选参数的名称,但更优雅的解决方案是为“必需的命名参数”(或您想要的任何名称)创建另一个组:

parser = argparse.ArgumentParser(description='Foo')
parser.add_argument('-o', '--output', help='Output file name', default='stdout')
requiredNamed = parser.add_argument_group('required named arguments')
requiredNamed.add_argument('-i', '--input', help='Input file name', required=True)
parser.parse_args(['-h'])
usage: [-h] [-o OUTPUT] -i INPUT

Foo

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output file name

required named arguments:
  -i INPUT, --input INPUT
                        Input file name

【讨论】:

我也遇到了同样的问题。我试过你的解决方案。它确实将参数添加到新组,但之后我的代码似乎不起作用。任何解决方案将不胜感激。链接到我的代码 - pastebin.com/PvC2aujz @ZararMahmud:您在代码的第 24 行传递了空参数:parser.parse_args([]) 相反,使用不带参数的parser.parse_args() 来捕获 sys.argv 的内容。每argparse @poke:不错的解决方案!但这在您需要互斥组的情况下无济于事,还是我遗漏了什么? @Judge 我会推荐阅读这个pymotw.com/3/argparse/#mutually-exclusive-options @mrgloom 选项通常用-- 和一个准确的名称来定义它们的用途。然后可以使用单个- 为常用选项定义一个短别名。在我的示例中,您可以将--output out.txt-o out.txt 用于完全相同的事情。 -o 只是 --output 的简称。一些命令行工具还允许您链接这些短别名。例如。 tar -xf archive.tartar --extract --file=archive.tar 的缩写。【参考方案2】:

由于我更喜欢​​在可选参数之前列出必需的参数,所以我通过以下方式解决它:

parser = argparse.ArgumentParser()
parser._action_groups.pop()
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')
return parser.parse_args()

这个输出:

usage: main.py [-h] --required_arg REQUIRED_ARG [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  --optional_arg OPTIONAL_ARG

我可以不用-h, --help 出现在可选参数组中。

【讨论】:

这真的会强制 argparse 按要求处理任何参数吗? 我认为在添加参数时仍然需要设置'required'参数。 那真是太好了。 @Anthony - 不,你需要 add_argument 中的 'required=True' 。上面的答案只是说明了参数分组。 现在在第一行,它看起来好像参数是可选的,所以与 OP 显示的相反。是否有可能在可选参数之前显示必需的参数并且没有括号?【参考方案3】:

以@Karl Rosaen 为基础

parser = argparse.ArgumentParser()
optional = parser._action_groups.pop() # Edited this line
required = parser.add_argument_group('required arguments')
# remove this line: optional = parser...
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')
parser._action_groups.append(optional) # added this line
return parser.parse_args()

这个输出:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

【讨论】:

顺便说一句,有什么方法(方法)如何在不访问受保护成员的情况下访问_action_group?在我的情况下,我需要向已经存在的(自定义)组添加一些参数。 这很棒。解决出现在第二个可选列表中的 --help 项目。 注意:这个答案破坏了暴露的 API,检查下面的answer by Bryan_D。【参考方案4】:

再来一次,以@RalphyZ 为基础

这不会破坏暴露的 API。

from argparse import ArgumentParser, SUPPRESS
# Disable default help
parser = ArgumentParser(add_help=False)
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')

# Add back help 
optional.add_argument(
    '-h',
    '--help',
    action='help',
    default=SUPPRESS,
    help='show this help message and exit'
)
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')

这将显示与上面相同并且应该在未来的版本中保留:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

【讨论】:

你能解释一下 RalphyZ 的回答是如何破坏暴露的 API 的吗? _action_groups 仅供内部使用。因此,没有跨版本的兼容性保证。【参考方案5】:

默认情况下,parser._action_groups 中有 2 个参数组:位置参数和命名参数(标题为“可选参数”)。 您可以将命名的可选参数添加到现有的“可选参数”组,并将所需的命名参数添加到新的“必需参数”组。之后,您可以重新排序组:

import argparse

parser = argparse.ArgumentParser(description='Foo')

required = parser.add_argument_group('required arguments')

required.add_argument('-i','--input', help='Input file name', required=True)
parser.add_argument('-o','--output', help='Output file name', default="stdout")

groups_order = 
    'positional arguments': 0,
    'required arguments': 1,
    'optional arguments': 2

parser._action_groups.sort(key=lambda g: groups_order[g.title])

parser.parse_args(['-h'])

输出:

usage: argparse_argument_groups.py [-h] -i INPUT [-o OUTPUT]

Foo

required arguments:
  -i INPUT, --input INPUT
                        Input file name

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output file name

【讨论】:

【参考方案6】:

您不需要覆盖可选组。

只要做:

parser = argparse.ArgumentParser()
required = parser.add_argument_group('required arguments')
required.add_argument('--required_arg', required=True)
# All arguments set via parser directly will automatically go to the optional group
parser.add_argument('--optional_arg')
parser.print_help()

会打印出来

usage: [-h] --required_arg REQUIRED_ARG [--optional_arg OPTIONAL_ARG]

optional arguments:
  -h, --help            show this help message and exit
  --optional_arg OPTIONAL_ARG

required arguments:
  --required_arg REQUIRED_ARG

如果您希望在可选参数之前有必需的参数,您可以执行以下操作:

parser = argparse.ArgumentParser()
optional = parser._action_groups.pop()
required = parser.add_argument_group('required arguments')
parser._action_groups.append(optional)
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')
parser.print_help()

将以正确的顺序打印组:

usage: [-h] --required_arg REQUIRED_ARG [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help            show this help message and exit
  --optional_arg OPTIONAL_ARG

【讨论】:

【参考方案7】:

在使用 argparse 时,所需的参数通常是“位置”参数。

    parser = argparse.ArgumentParser(description="Foo")
    parser.add_argument("username")
    parser.add_argument("password")

这将添加两个必需的位置参数。

【讨论】:

以上是关于Argparse:“可选参数”下列出的必需参数?的主要内容,如果未能解决你的问题,请参考以下文章

使用不需要指定输出文件名的可选参数运行 argparse

如何让 argparse 识别跟随可变长度可选参数的位置参数?

python argparse - 要么两个可选参数,要么一个都没有

Argparse - 子解析器中位置参数之前的可选参数

Python argparse 以不同的方式处理参数

Dart 知识点:可选参数必需参数