如何避免在Python的argparse模块中使用大写占位符?

13

有一个问题问它们来自哪里,而被接受的答案是一堆指向教程和源代码的链接。 argparse python模块行为的解释:大写占位符从哪里来?

对我来说,这些链接都没有帮助,我要么想摆脱它们,要么知道它们的目的。

举个例子,像这样的一行:

parser.add_argument('-c', '--chunksize', type=int, help='chunk size in bits')

会产生这样的垃圾:

optional arguments:
  -h, --help            show this help message and exit
  -c CHUNKSIZE, --chunksize CHUNKSIZE
                        chunk size in bits

如果我尝试使用空的元变量字符串:

parser.add_argument('-c', '--chunksize', metavar='', type=int, help='chunk size in bits')

逗号后面会有一个空格:

optional arguments:
  -h, --help            show this help message and exit
  -c , --chunksize      chunk size in bits

我认为 argparse.SUPPRESS 可能会起作用,但显然不是这样... - mgilson
你想要的输出是什么?使用-c chunksize, --chunksize chunksize代替-c CHUNKSIZE, --chunkesize CHUNKSIZE?那么metavar = ('chunksize')就可以实现。对于该参数不需要任何帮助行吗?使用help=argparse.SUPPRESS - Nisan.H
就我个人而言,我认为默认行为更好——它更明确哪些选项需要参数(以及需要多少个)。当然,我不是在编写程序,所以我的意见可能并不重要(这很好)——我只是表达了自己的感受。 - mgilson
@Nisan.H -- 我认为 OP 是想要 -c,--chunksize ______ 按比特计算的块大小 - mgilson
另外,可以查看 http://docs.python.org/dev/library/argparse.html#formatter-class 上的 MetavarTypeHelpFormatter。如果那不起作用,您可以获取源代码并子类化自己的格式化程序以按所需方式格式化内容。 - Nisan.H
我刚刚注意到MetavarTypeHelpFormatter仅适用于3.3及以上版本。我将为自定义格式编写一个答案。 - Nisan.H
3个回答

15
parser.add_argument('-c', '--chunksize', metavar='\b', type=int, help='chunk size in bits')

似乎可以工作


2
真是个巧妙的技巧,哈哈。我简直不敢相信这是正确的做法。 - bug
1
你自己都说了,这只是个hack,所以不可能是正确的方式,哈哈 - Aravind
5
这将破坏选项描述的缩进。 - user1948847

5
你可以创建一个格式化类,以你想要的任何方式格式化参数。这并不是完全直接的,但是以下是一个能够生成如下输出的示例(假设@mgilson正确地认为你只想为一组命令名称显示一次元变量...否则,只需指定一个实际的metavar ='value'即可精确地显示该文本。):
# without metavar specified:
-c, --chunksize CHUNKSIZE
                chunk size in bits
# with metavar specified:
-c, --chunksize some_metavar
                chunk size in bits

以下是该类的代码以及产生两个输出的方式:

import argparse
# 2.7-3.2
class SingleMetavarHelpFormatter(argparse.HelpFormatter):
    def _format_action_invocation(self, action):
        if not action.option_strings:
            metavar, = self._metavar_formatter(action, action.dest)(1)
            return metavar

        else:
            parts = []

            # if the Optional doesn't take a value, format is:
            #    -s, --long
            if action.nargs == 0:
                parts.extend(action.option_strings)

            # if the Optional takes a value, format is:
            #    -s ARGS, --long ARGS
            else:
                default = action.dest.upper()
                args_string = self._format_args(action, default)

                ## THIS IS THE PART REPLACED
                #~ for option_string in action.option_strings:
                    #~ parts.append('%s %s' % (option_string, args_string)) ### this is change
                ## /SECTION REPLACED

                ## NEW CODE:
                parts.extend(action.option_strings)
                parts[-1] += ' %s' % args_string
                ## /NEW CODE
            return ', '.join(parts)


parser = argparse.ArgumentParser(
    prog='PROG',
    formatter_class=SingleMetavarHelpFormatter
    )

parser.add_argument('-c', '--chunksize', type=int, help='no metavar specified')
parser.add_argument('-w', '--with_metavar', type=int, help='metavar specified', metavar='some_metavar')

parser.print_help()

编辑: 如果不想显示元变量(metavar),可以将空字符串传递给metavar参数:

parser.add_argument('-e', '--with_empty_metavar', type=int, help='empty metavar specified', metavar='')

使用原始类和新类的区别在于短命令语法后面缺少额外的空格字符。
#usage: PROG [-h] [-c CHUNKSIZE] [-w some_metavar] [-e]
#
#optional arguments:
#  -h, --help            show this help message and exit
#  -c CHUNKSIZE, --chunksize CHUNKSIZE
#                        no metavar specified
#  -w some_metavar, --with_metavar some_metavar
#                        metavar specified
#  -e, --with_empty_metavar
#                        empty metavar specified

但是我为什么要一开始就有这个 metavar 呢?如果我查看 Linux 命令行应用程序中的典型帮助消息,我不会看到这个 metavar 行。 - bug
如果您将空字符串作为 metavar 传递,则会显示为空。我已在编辑中包含它。 - Nisan.H
谢谢,这样我就可以编写自己的格式化程序来使其工作了。我仍然不明白为什么这必须如此繁琐,为什么它不是默认行为。 - bug
没有特定的模块开发背景或者 Linux 命令行应用程序帮助信息标准,我认为一个需要参数的命令应该显示一些占位符来表示它的位置(有时还包括类型)... 就我个人而言,这也是我喜欢 Python 的原因之一——它非常容易改变这种内置行为以适应自己的需求。 - Nisan.H

1
关于您对大写 metavar 的目的的问题 - 文档中说:

一个可选的单参数 --foo,后面应该跟一个命令行参数,将被称为 FOO

这是解释,但我不得不多次阅读才意识到它的简单含义是 FOO 是提供参数的提示,其中参数值=FOO。因此,使用比 foo 更有用的示例:
# --days DAYS   <-- from an imaginary help page
--days 365  # for a year; DAYS=365
--days 7    # for a week; DAYS=7 

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