我将Python3 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
我的意思是,参数和值在一个字符串上,描述在另一个字符串上,即使控制台右侧有足够的空间将其放在一行中。就像第一参数--help
一样。当您有30-40个参数时,命令行帮助的可读性确实变差了
答案 0 :(得分:5)
argparse
默认情况下会限制option + 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
,则可以使用{{ 1}}。例如:
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
并按照this question中的说明使用formatter_class
。但是,这不是该模块的公共API的一部分。我不知道他们何时没有向公共API中添加至少两个有用的参数。
您可能仍想指定一个max_help_position
:
metavar
输出将是:
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
env变量,可能对此很有用)来决定COLUMNS
的值,在那种情况下最好。
要在一条线上(假设端子足够大)上获得所有参数帮助:
max_help_position
答案 1 :(得分:1)
当前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
类确实具有几个关键字参数:
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)
您还可以将HelpFormatter
子类化以自定义格式。这就是RawTextHelpFormatter
之类的替代方法。
来自argparse文档:
formatter_class
ArgumentParser对象允许通过指定备用格式设置类来自定义帮助格式。当前,有四个这样的类:
提供和列出这4个类并不是限制性的。允许甚至鼓励其他自定义。
在https://bugs.python.org/issue13023中,argparse
的原始作者Steven Bethard提倡编写自己的格式化程序类:
您的解决方案实际上是当前推荐的解决方案-将您要合并的两个类混合在一起,并将子类作为参数传递。这可能应该记录在某个地方(并进行更多测试)。
他在说的是:
class myFormatter(argparse.RawDescriptionHelpFormatter,
argparse.ArgumentDefaultsHelpFormatter):
pass
3年前我谈到了max_help_position
的使用:
https://bugs.python.org/issue25297 max_help_position is not works in argparse library
还有一个SO问题:
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
我不会担心max_help_position
参数消失或被禁用。如果我对此有任何发言权,那么任何提议的更改都会被拒绝,理由是它可能存在向后兼容性问题。
在实践中,最简单的方法是更改文档以匹配代码,或更好地说明含糊之处。在这种情况下,可以记录对lambda
的{{1}}调用。我也可以想象定义一个功能相同的小函数。当没有机会伤害现有用户时,添加功能是最简单的。