Py学习  »  Python

python argparse:增加参数和描述之间的空间

Yuri S. Cherkasov • 6 年前 • 1813 次点击  

我在用蟒蛇3 argparse 用于复杂的命令行界面。很多争论,其中一些是“冗长”的,以避免误解。

parser = argparse.ArgumentParser(description='Command-line interface')
parser.add_argument('--long-param-one',
                    help='Long param one description',
                    dest='lond_param_one',
                    required=True)

parser.add_argument('--long-param-two',
                    help='Long param two description',
                    dest='lond_param_two',
                    required=True)

当参数名足够长并且目标变量也足够长时,当使用 --help

Command-line interface

optional arguments:
  -h, --help            show this help message and exit
  --long-param-one LONG_PARAM_ONE
                        Long param one description
  --long-param-two LONG_PARAM_TWO
                        Long param two description

我的意思是,参数和值在一个字符串上,描述在另一个字符串上,即使控制台右侧有足够的空间,所以可以将其放在一行中。就像fisrt参数 --帮助 做。当您有30-40个参数时,命令行帮助的可读性会变得更糟。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/38998
文章 [ 2 ]  |  最新文章 6 年前
hpaulj
Reply   •   1 楼
hpaulj    7 年前

当前 HelpFormatter 是否检查 os.environ['COLUMNS'] 用于终端宽度。但这不会动态更新,甚至可能无法设置。

有一个补丁

https://bugs.python.org/file24602/issue13041.patch argparse: terminal width is not detected properly

这显然是最近放进3.8的,看 shutil.get_terminal_size().columns 相反。


至于为什么 argparse 不提供更直接的宽度控制-设计理念已允许自定义 formatter_class 规范,而不是一组(可能)大的格式化参数。大多数参数 ArgumentParser 与解析有关,而不是帮助格式化。其目标是允许完全定制,而不会将输入与许多很少使用的参数混淆。

这个 帮助格式化程序 类不接受几个关键字参数:

HelpFormatter.__init__(self, prog, indent_increment=2, max_help_position=24, width=None)

但是,当前创建格式化程序的方法只是通过 prog 参数。

Giacomo的答案显示了如何指定这些其他参数:

formatter = lambda prog: argparse.HelpFormatter(prog,max_help_position=52)

你也可以子类 帮助格式化程序 自定义格式。这就是备选方案喜欢的 RawTextHelpFormatter 做。

有关自定义格式化程序的详细信息

从argparse文档中:

格式化程序类

ArgumentParser对象允许通过指定备用格式类自定义帮助格式。目前,这类课程有四个:

提供并列出这4个类并不意味着有限制。其他定制是允许的,甚至是鼓励的。

https://bugs.python.org/issue13023 ,史蒂文·贝萨德,原作者 argparse ,提倡编写自己的格式化程序类:

您的解决方案实际上是当前推荐的解决方案——将两个您想要组合的类混合在一起,并将子类作为参数传递。这可能会被记录在某个地方(并测试更多)。

他说的混合是:

class myFormatter(argparse.RawDescriptionHelpFormatter,
                  argparse.ArgumentDefaultsHelpFormatter):
    pass

我提到了 max_help_position 3年前:

https://bugs.python.org/issue25297 max_help_position is not works in argparse library

还有一个问题:

max_help_position is not works in python argparse library

中的其他示例 argparse 允许您提供自定义类或函数的地方包括:

https://docs.python.org/3/library/argparse.html#action-classes https://docs.python.org/3/library/argparse.html#the-namespace-object https://docs.python.org/3/library/argparse.html#customizing-file-parsing https://docs.python.org/3/library/argparse.html#type

我不会担心 最大帮助位置 参数消失或被禁用。如果我在这件事上有任何发言权,像这样的任何提议的变更都将被拒绝,理由是它可能存在向后兼容性问题。

在实践中,最容易更改文档以匹配代码,或者更好地说明模糊的点。在这种情况下, lambda 呼叫 帮助格式化程序 可以被记录下来。我还可以想象定义一个执行相同操作的小函数。在不可能伤害现有用户的情况下,添加功能是最简单的。

Giacomo Alzetta
Reply   •   2 楼
Giacomo Alzetta    7 年前

argparse 默认情况下,限制选项+metavar所占用的最大空间,并将在单独的行上写入帮助消息,即使终端足够大,可以同时容纳这两个选项。

考虑这个示例脚本:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--name', help='help help')
parser.add_argument('--parameter', help='help help')
parser.add_argument('--parameter-name', help='help help')
parser.add_argument('--this-parameter-name', help='help help')
parser.add_argument('--this-is-parameter-name', help='help help')
parser.add_argument('--this-is-a-parameter-name', help='help help')
parser.add_argument('--this-is-a-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-very-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-very-very-long-parameter-name', help='help help')

parser.parse_args()

结果输出如下:

usage: a.py [-h] [--name NAME] [--parameter PARAMETER]
            [--parameter-name PARAMETER_NAME]
            [--this-parameter-name THIS_PARAMETER_NAME]
            [--this-is-parameter-name THIS_IS_PARAMETER_NAME]
            [--this-is-a-parameter-name THIS_IS_A_PARAMETER_NAME]
            [--this-is-a-long-parameter-name THIS_IS_A_LONG_PARAMETER_NAME]
            [--this-is-a-very-long-parameter-name THIS_IS_A_VERY_LONG_PARAMETER_NAME]
            [--this-is-a-very-very-long-parameter-name THIS_IS_A_VERY_VERY_LONG_PARAMETER_NAME]
            [--this-is-a-very-very-very-long-parameter-name THIS_IS_A_VERY_VERY_VERY_LONG_PARAMETER_NAME]

optional arguments:
  -h, --help            show this help message and exit
  --name NAME           help help
  --parameter PARAMETER
                        help help
  --parameter-name PARAMETER_NAME
                        help help
  --this-parameter-name THIS_PARAMETER_NAME
                        help help
  --this-is-parameter-name THIS_IS_PARAMETER_NAME
                        help help
  --this-is-a-parameter-name THIS_IS_A_PARAMETER_NAME
                        help help
  --this-is-a-long-parameter-name THIS_IS_A_LONG_PARAMETER_NAME
                        help help
  --this-is-a-very-long-parameter-name THIS_IS_A_VERY_LONG_PARAMETER_NAME
                        help help
  --this-is-a-very-very-long-parameter-name THIS_IS_A_VERY_VERY_LONG_PARAMETER_NAME
                        help help
  --this-is-a-very-very-very-long-parameter-name THIS_IS_A_VERY_VERY_VERY_LONG_PARAMETER_NAME
                        help help

最简单的方法 尝试 要避免此问题,请指定 metavar 显式地使用一个短值,因此改为ov THIS_IS_A_VERY_VERY_VERY_LONG_PARAMETER_NAME 你可以用,比如, X 。例如:

import argparse

parser = argparse.ArgumentParser()
m = 'X'
parser.add_argument('--name', help='help help', metavar=m)
parser.add_argument('--parameter', help='help help', metavar=m)
parser.add_argument('--parameter-name', help='help help', metavar=m)
parser.add_argument('--this-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-very-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-very-very-long-parameter-name', help='help help', metavar=m)

parser.parse_args()

结果是:

usage: a.py [-h] [--name X] [--parameter X] [--parameter-name X]
            [--this-parameter-name X] [--this-is-parameter-name X]
            [--this-is-a-parameter-name X] [--this-is-a-long-parameter-name X]
            [--this-is-a-very-long-parameter-name X]
            [--this-is-a-very-very-long-parameter-name X]
            [--this-is-a-very-very-very-long-parameter-name X]

optional arguments:
  -h, --help            show this help message and exit
  --name X              help help
  --parameter X         help help
  --parameter-name X    help help
  --this-parameter-name X
                        help help
  --this-is-parameter-name X
                        help help
  --this-is-a-parameter-name X
                        help help
  --this-is-a-long-parameter-name X
                        help help
  --this-is-a-very-long-parameter-name X
                        help help
  --this-is-a-very-very-long-parameter-name X
                        help help
  --this-is-a-very-very-very-long-parameter-name X
                        help help

这已经好了很多,但是正如您可以看到的,参数名很长,它仍然不会将所有文本写在一行上。

实现所需目标的唯一方法是指定 formatter_class 并使用 max_help_position 如中所述 this question . 但是,这不是模块的公共API的一部分。我不知道他们什么时候没有向公共API添加至少两个有用的参数。

您可能仍要指定 元变量 :

import argparse

formatter = lambda prog: argparse.HelpFormatter(prog,max_help_position=52)
parser = argparse.ArgumentParser(formatter_class=formatter)
m = 'X'
parser.add_argument('--name', help='help help', metavar=m)
parser.add_argument('--parameter', help='help help', metavar=m)
parser.add_argument('--parameter-name', help='help help', metavar=m)
parser.add_argument('--this-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-very-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-very-very-long-parameter-name', help='help help', metavar=m)

parser.parse_args()

输出将是:

usage: a.py [-h] [--name X] [--parameter X] [--parameter-name X]
            [--this-parameter-name X] [--this-is-parameter-name X]
            [--this-is-a-parameter-name X] [--this-is-a-long-parameter-name X]
            [--this-is-a-very-long-parameter-name X]
            [--this-is-a-very-very-long-parameter-name X]
            [--this-is-a-very-very-very-long-parameter-name X]

optional arguments:
  -h, --help                                        show this help message and
                                                    exit
  --name X                                          help help
  --parameter X                                     help help
  --parameter-name X                                help help
  --this-parameter-name X                           help help
  --this-is-parameter-name X                        help help
  --this-is-a-parameter-name X                      help help
  --this-is-a-long-parameter-name X                 help help
  --this-is-a-very-long-parameter-name X            help help
  --this-is-a-very-very-long-parameter-name X       help help
  --this-is-a-very-very-very-long-parameter-name X  help help

您可能会尝试确定终端的大小(大多数终端都提供 WIDTH COLUMNS env变量,可用于确定 最大帮助位置 在那种情况下那是最好的。


要使所有参数在一行上都有帮助(假设足够大的终端),您需要:

max_help_position >= max(len(param.name)+len(param.metavar) for param in params)