在参数帮助字符串中访问“隐式”元变量值

时间:2018-06-28 14:30:28

标签: python argparse

如果您在没有明确动作的情况下在add_argument上调用argparse.ArgumentParser(),则会得到"store"动作。在自动生成的--help输出中,除非设置metavar,否则将获得long选项的大写字母:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--version', metavar='X.Y.Z')
parser.add_argument('--date'),
parser.parse_args(['--help'])

显示:

usage: try.py [-h] [--version X.Y.Z] [--date DATE]

optional arguments:
  -h, --help       show this help message and exit
  --version X.Y.Z
  --date DATE

在这种情况下,我将X.Y.Z称为显式metavar,将DATE称为隐式metavar。

如果您想获得更多有用的帮助,可以执行以下操作:

parser.add_argument('--version', metavar='X.Y.Z', 
                    help = "set version to % (metavar)s")

给出(仅显示更改的行):

  --version X.Y.Z  set version to X.Y.Z

并且能够在帮助字符串中使用该%(metavar)s很不错,因为当您更改metavar='MAJOR.MINOR'时,不需要更新帮助(您肯定会忘记)。

但是,如果您为--date参数添加帮助,则使用隐式metavar:

parser.add_argument('--date', 
                    help="use %(metavar)s instead of today's date")

您得到:

  --date DATE      use None instead of today

None既不是我期望的,也不是我想要的。

当然,我总是可以在帮助中对'DATE'进行硬编码,或显式提供metavar(尤其是在帮助字符串中使用它时)。但是当我这样做时,当我更改long选项的名称时,我一定会忘记更新metavar。

是否有一种“自动”方法来获取帮助字符串中的DATE而不是None
还是我在使用%(metavar)s的地方应该使用其他东西(如果使用的话,该怎么办)?

2 个答案:

答案 0 :(得分:1)

在调用parser.parse_args()之前,您可以做的一件事就是更新添加到parser且具有metavar属性为None的那些动作:

for action in parser._actions:
    if not hasattr(action, 'metavar') or not hasattr(action, 'dest'):
        continue
    metavar = getattr(action, 'metavar')
    if metavar is None:
        action.metavar = action.dest.upper()

生成的输出如下:

  --version X.Y.Z  set version to X.Y.Z
  --date DATE      use DATE instead of today

但是正如我们在BDFL的母语中所说:“ mooi是安德斯”¹


¹美丽的外观与众不同

答案 1 :(得分:0)

这并不容易,至少不在argparse之内。

add_argument会创建一个Action类对象,并分配属性:

 a1 = parser.add_argument('--version', metavar='X.Y.Z')
 a2 = parser.add_argument('--date')

a1.metavar将是'X.Y.Z'a2.metavar将是默认的None

这是帮助行中使用的值,例如:

`'help %(metavar)`%{'metavar':action.metavar}'

action.metavar属性可以在创建操作后进行修改,如其他答案所示。

但是对于usagehelp的第一部分,它的功能类似于:

def _metavar_formatter(self, action, default_metavar):
        if action.metavar is not None:
            result = action.metavar
        elif action.choices is not None:
            choice_strs = [str(choice) for choice in action.choices]
            result = '{%s}' % ','.join(choice_strs)
        else:
            result = default_metavar
        ...

default_metavar对于positionalsoptionals是不同的,但基本上是从action.dest派生的。因此,显示的metavar是动态生成的,不会存储在任何地方。


%(metavar)s的处理方式为:

def _expand_help(self, action):
    params = dict(vars(action), prog=self._prog)
    for name in list(params):
        if params[name] is SUPPRESS:
            del params[name]
    for name in list(params):
        if hasattr(params[name], '__name__'):
            params[name] = params[name].__name__
    if params.get('choices') is not None:
        choices_str = ', '.join([str(c) for c in params['choices']])
        params['choices'] = choices_str
    return self._get_help_string(action) % params

vars(action)根据action的所有属性创建字典。

我可以想象创建一个Formatter子类来修改一个或多个方法。现有的子类仅通过修改一个或两个低级方法即可工作。但这需要研究代码。


In [329]: p = argparse.ArgumentParser()
In [330]: a1 = p.add_argument('--version', metavar='X.Y.Z')
In [331]: a1
Out[331]: _StoreAction(option_strings=['--version'], dest='version', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar='X.Y.Z')
In [332]: vars(a1)
Out[332]: 
{'option_strings': ['--version'],
 'dest': 'version',
 'nargs': None,
 'const': None,
 'default': None,
 'type': None,
 'choices': None,
 'required': False,
 'help': None,
 'metavar': 'X.Y.Z',
 'container': <argparse._ArgumentGroup at 0x7f72ecc4b4a8>}

有关多个参数的帮助:

In [333]: a1.help='help %(metavar)s, %(dest)s, %(required)s'
In [334]: p.print_help()
usage: ipython3 [-h] [--version X.Y.Z]

optional arguments:
  -h, --help       show this help message and exit
  --version X.Y.Z  help X.Y.Z, version, False