Argparse 建议在帮助文本使用行中使用无意义的顺序

Argparse suggests nonsensical order in help text usage line

这个节目:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('files', metavar='INPUT', nargs='*',
    help='File(s) containing words to include. If none given, stdin will be used.')
parser.add_argument('-x', '--exclude', nargs='*',
    help='File(s) containing words to exclude.')
args = parser.parse_args()
print args.files
print args.exclude

在 Python 2.7.9:

中 运行 时产生此输出
$ python prog.py --help
usage: prog.py [-h] [-x [EXCLUDE [EXCLUDE ...]]] [INPUT [INPUT ...]]

positional arguments:
  INPUT                 File(s) containing words to include. If
                        none given, stdin will be used.

optional arguments:
  -h, --help            show this help message and exit
  -x [EXCLUDE [EXCLUDE ...]], --exclude [EXCLUDE [EXCLUDE ...]]
                        File(s) containing words to exclude.

但是,"help" 输出指示用户对参数使用无意义的排序。这是荒谬的,因为如果使用 -x 选项,则不会检测到 INPUT 个参数。

Argparse 应该改为建议用户使用此顺序:

usage: prog.py [-h] [INPUT [INPUT ...]] [-x [EXCLUDE [EXCLUDE ...]]]

两个问题:

  1. 这是 argparse 中的错误吗? (我认为是。)
  2. 不管它是否是一个错误,我怎样才能修复它以便 $ python prog.py --help 输出我想要的帮助文本(见上文),最好是尽可能 DRY 的方式?

最简单的方法是将usage="..."添加到argparse.ArgumentParser()

通过查看 argparse 的源代码,我找到了一种求助于可能有点脏的参数的方法:

class MyHelpFormatter(argparse.HelpFormatter):

    def _format_actions_usage(self, actions, groups):
        actions.sort(key=lambda a: bool(a.option_strings and a.nargs != 0))
        return super(MyHelpFormatter, self)._format_actions_usage(actions, groups)

parser = argparse.ArgumentParser(formatter_class = MyHelpFormatter)

在输入选项中添加'-f', '--files'

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--files', metavar='INPUT', nargs='*', required=True,
    help='File(s) containing words to include. If none given, stdin will be used.')
parser.add_argument('-x', '--exclude', nargs='*',
    help='File(s) containing words to exclude.')
args = parser.parse_args()
print args.files

显示:

usage: argparse_test.py [-h] [-f [INPUT [INPUT ...]]]
                    [-x [EXCLUDE [EXCLUDE ...]]]

optional arguments:
  -h, --help            show this help message and exit
  -f [INPUT [INPUT ...]], --files [INPUT [INPUT ...]]
                        File(s) containing words to include. If none given,
                        stdin will be used.
  -x [EXCLUDE [EXCLUDE ...]], --exclude [EXCLUDE [EXCLUDE ...]]
                    File(s) containing words to exclude.
print args.exclude

您可以将 'files' 设为必需。来自文档:

In general, the argparse module assumes that flags like -f and --bar indicate optional arguments, which can always be omitted at the command line. To make an option required, True can be specified for the required= keyword argument to add_argument():

生成 usage 行时,带标记的参数放在最前面,位置在后面。这符合常见的命令行用法。它不会努力评估这是否是最佳选择。

解决此问题的最简单方法是提供自定义 usage 参数。

(关于更改使用行中参数顺序的问题。解决方案需要自定义 HelpFormatter class。 )

正如您所注意到的,当 * 位置放在 * 可选之后时,所有参数都分配给可选。您可以使用 '--' 来分隔两个参数列表。

有一个带有补丁的 bug/issue 当 positional 采用已知数量的参数(例如默认参数)时应该改进处理。它通过注意到位置需要一个参数来做到这一点,因此它为它保留了一个。但是在 * * 的情况下, positional 满足 none,因此它无法知道如何在 2.

之间拆分参数

我喜欢将 postional 变成标记论点的想法。这应该可以减少许多 * 参数中固有的歧义。