Argparse:如何在“--help”中包含默认值?

448
假设我有以下 argparse 代码片段:
diags.cmdln_parser.add_argument( '--scan-time',
                     action  = 'store',
                     nargs   = '?',
                     type    = int,
                     default = 5,
                     help    = "Wait SCAN-TIME seconds between status checks.")

目前,--help 返回:

usage: connection_check.py [-h]
                             [--version] [--scan-time [SCAN_TIME]]

          Test the reliability/uptime of a connection.



optional arguments:
-h, --help            show this help message and exit
--version             show program's version number and exit
--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.

我更喜欢这样的方式:

--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.
                    (Default = 5)

查看帮助格式化代码后发现选项有限。是否有巧妙的方式可以让argparse以类似的方式打印--scan-time的默认值,或者我应该只是子类化help格式化程序?


7
您可能对docopt感兴趣。我再也没有考虑过argparse了。 - Paulo Scardine
31
argparse内置语言是一个重要的优势。 - jordanm
1
@PauloScardine:将一个非标准库引入到我的当前项目中确实会很麻烦,但我确实喜欢docopt的输出效果。感谢您的提示! - JS.
@JS。你说“将一个非标准库引入我的当前项目确实会很麻烦”。真的吗?在pypi上有很多非常有用的库。在我的情况下,引入一个非标准库很容易。如果在你的情况下很难,那就很遗憾了。 - guettli
5
那个项目是为商业嵌入式项目而设计的。你说得对,安装很容易。但从公司法务部门获得批准却是一场噩梦。 - JS.
4个回答

657

使用argparse.ArgumentDefaultsHelpFormatter格式化程序

parser = argparse.ArgumentParser(
    # ... other options ...
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

引用文档

另一个可用的格式化类ArgumentDefaultsHelpFormatter,将添加关于每个参数的默认值信息。

请注意:这仅适用于具有定义帮助文本的参数;对于没有帮助文本定义的参数,没有帮助信息可以添加有关默认值的信息

然后,您扫描时间选项的精确输出如下:

  --scan-time [SCAN_TIME]
                        Wait SCAN-TIME seconds between status checks.
                        (default: 5)

23
我能否控制只有在显式指定'default='的参数才显示默认值?因为我不喜欢出现“默认值:None”这样的文本。 - Ziyuan
28
您可以将default设置为SUPPRESSdefault=argparse.SUPPRESS。请注意,如果省略了该参数,则不会将任何属性添加到命名空间结果中(参见default文档)。 - Martijn Pieters
10
请注意,您需要为创建的每个子解析器指定此选项。 - KomodoDave
2
如果我已经设置了formatter_class,我该怎么办? - Azor Ahai -him-
7
请创建一个新类,它继承自两个类并将其用作格式化程序。例如:class RawTextArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter): pass, parser = argparse.ArgumentParser(..., formatter_class=RawTextArgumentDefaultsHelpFormatter)。这两个变量覆盖了基本帮助格式化程序的两个不同方面,因此可以轻松地组合在一起。 - Martijn Pieters
显示剩余6条评论

294

'%(default)s' 添加到 help 参数以控制显示内容。

parser.add_argument("--type", default="toto", choices=["toto","titi"],
                              help = "type (default: %(default)s)")

注意:

  • 在默认值括号中添加格式字符(不要与format或f-string中的花括号{default}混淆),表示为百分号%
  • 不要忘记在最后加上类型表示的“格式说明符”(例如字符串s,整数d,浮点数f等)
  • 您还可以添加常规的“printf”格式说明符(如浮点数位数,前导零等)

更多详细信息请参见printf文档


20
我喜欢这个选项,因为我已经使用了format_class=argparse.RawTestHelpFormatter格式,并且不想在OOP上浪费时间。 - mqsoh
32
不要忘记在格式化字符串中包含变量'type'--例如,对于字符串使用'%(default)s',对于数字使用'%(default)d'。 - strongMA
6
我更喜欢这个解决方案,它更加简单,而且我不需要显式地处理没有默认值的参数。 - void.pointer
1
我喜欢这个,因为更改格式化程序类会在帮助中添加一堆“(默认值:无)” ,这会使其变得混乱。 - Caleb Stanford
@Noldorin 在我的3.8.1安装中完美运行。你确定使用的是%(default)s而不是{default}吗?(即用括号而不是花括号) - Jean-Francois T.
显示剩余4条评论

22

包装类

这是我迄今为止发现的最可靠和DRY(不重复,无冗余)的方法,既可以显示默认值,又可以同时使用其他格式化程序,比如argparse.RawTextHelpFormatter

#!/usr/bin/env python3

import argparse

class ArgumentParserWithDefaults(argparse.ArgumentParser):
    def add_argument(self, *args, help=None, default=None, **kwargs):
        if help is not None:
            kwargs['help'] = help
        if default is not None and args[0] != '-h':
            kwargs['default'] = default
            if help is not None:
                kwargs['help'] += ' Default: {}'.format(default)
        super().add_argument(*args, **kwargs)

parser = ArgumentParserWithDefaults(
    formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.add_argument('--no-default', help='''my help
for no-default''')
parser.add_argument('--no-help', default=101)

parser.print_help()
print()
print(parser.parse_args())

输出:

usage: main.py [-h] [-a A] [-b B] [--no-default NO_DEFAULT]
               [--no-help NO_HELP]

optional arguments:
  -h, --help            show this help message and exit
  -a A                  my help
                        for a Default: 13
  -b B                  my help
                        for b Default: 42
  --no-default NO_DEFAULT
                        my help
                        for no-default
  --no-help NO_HELP

Namespace(a=13, b=42, no_default=None, no_help=101)

ArgumentDefaultsHelpFormatter + RawTextHelpFormatter 多重继承

多重继承可以正常工作,但似乎不是公共API:

#!/usr/bin/env python3

import argparse

class RawTextArgumentDefaultsHelpFormatter(
    argparse.ArgumentDefaultsHelpFormatter,
    argparse.RawTextHelpFormatter
):
    pass

parser = argparse.ArgumentParser(
    formatter_class=RawTextArgumentDefaultsHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.print_help()

输出:

usage: a.py [-h] [-a A] [-b B]

optional arguments:
  -h, --help  show this help message and exit
  -a A        my help
              for a (default: 13)
  -b B        my help
              for b (default: 42)

它能够正常工作是因为我们可以从源代码 trivially 看到 https://github.com/python/cpython/blob/v3.6.5/Lib/argparse.py#L648 :

  • RawTextHelpFormatter 实现了 _split_lines
  • ArgumentDefaultsHelpFormatter 实现了 _get_help_string

所以我们可以猜测它们将很好地一起工作。

然而,这似乎不是公共 API,formatter_class 的方法也不是公共 API,因此我不认为目前有公共 API 的方法可以这样做。 argparse 文档字符串说:

本模块中的所有其他类都被认为是实现细节。(还要注意,HelpFormatter 和 RawDescriptionHelpFormatter 只被视为对象名称时公共的 —— 格式化程序对象的 API 仍然被认为是实现细节。)

另请参见:自定义 argparse 帮助消息

在 Python 3.6.5 上进行了测试。


1
太好了!终于有格式化的文档字符串和默认参数打印出来了。谢谢。 - Sylvain

7
通常情况下,自动包含帮助输出中的默认值很有用,但仅限于那些明确指定了默认值(使用default=..)。前面提到的方法在这方面存在一些缺陷:
  • ArgumentDefaultsHelpFormatter 方法会为每个未明确指定默认值的参数打印出(default: None),并为“标志”(action='store_true')打印出(default: False)。这会使帮助输出变得混乱。要避免这种情况,需要为每个这样的参数手动添加default=argparse.SUPPRESS

  • '%(default)s' 方法需要手动将其添加到我们想要在帮助中打印的所有参数的help字符串中。

这两种方法最终都需要手动干预才能打印出“正确”的默认值。自动执行此操作的一种方法是增强ArgumentDefaultsHelpFormatter,以忽略NoneFalse的默认值:

class ExplicitDefaultsHelpFormatter(argparse.ArgumentDefaultsHelpFormatter):
    def _get_help_string(self, action):
        if action.default in (None, False):
            return action.help
        return super()._get_help_string(action)

在需要时使用它来替换ArgumentDefaultsHelpFormatter

parser = argparse.ArgumentParser(
        formatter_class=ExplicitDefaultsHelpFormatter
                )

这将仅在帮助输出中打印明确设置的default值。
注意:如果参数的默认值明确设置为NoneFalse,则不会在此类帮助中显示;如果您希望在帮助输出中包含该参数,请将%(default)s字符串添加到help中。

1
这不会显示默认值为default=0的参数。替代方法:if action.default is None or action.default is False - sfinkens
@sfinkens 感谢你指出这个问题!这是因为在in检查中发生了隐式的intbool类型转换。我已经按照你的建议,将那一行代码替换为is测试。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接