Python argparse多个metavar名称

12

我正在使用 Python 中的 argparse 库。在某些时候,我使用一个名为 param 的参数,它接受两个参数:键和值。我使用的代码行如下:

parser.add_argument("-p", "--param", nargs=2, action="append", 
                    help="key and value for query", 
                    type=str, metavar="key value"
                    )

这里的问题是当我调用帮助时,它显示为:

optional arguments:
    -h, --help            show this help message and exit
    -p key value key value, --param key value key value
                          key and value for query parameters

“key value”这个名称重复了两次。我尝试使用列表和生成器,但我找到的唯一方法是创建一个包含不同值的小类,并在要求__str__时产生它们,就像这样:

class Meta:
    def __init__(self, iterable):
        self.gene = itertools.cycle(iterable)

    def __str__(self):
        return self.gene.__next__()

我这样调用add_argument

parser.add_argument("-p", "--param", nargs=2, action="append", 
                    help="key and value for query parameters",
                    type=str, metavar=Meta(["key", "value"])
                    )

而且它显示得很正常:

-p key value, --param key value
                    key and value for query parameters

但我觉得使用临时类 Meta 很丑陋,而且我感觉一定有其他(更好的)方法可以做到这一点。我这样做对吗?

2个回答

24

通过深入阅读doc,我找到了答案

nargs的不同值可能导致metavar使用多次。向metavar提供元组会为每个参数指定不同的显示方式:

实际上,这完美地起作用:

parser.add_argument("-p", "--param", nargs=2, action="append", 
                    help="key and value for query parameters",
                    type=str, metavar=("key", "value")
                    )

action="append" 是什么作用? - alper
action="append"是什么作用? - undefined
action="append" 将元素存储在列表中。https://docs.python.org/3/library/argparse.html#action - Thibault D.

1

元变量处理程序并不特别复杂,但确实利用了 tuple 类提供的信息。

你的类为什么有效并不明显,因此我深入研究了代码。

Formatter类中处理元变量的方式如下:

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

    def format(tuple_size):
        if isinstance(result, tuple):
            return result
        else:
            return (result, ) * tuple_size
    return format

并且

def _format_args(self, action, default_metavar):
    get_metavar = self._metavar_formatter(action, default_metavar)
    ....
    else:
        # for numeric nargs
        formats = ['%s' for _ in range(action.nargs)]
        result = ' '.join(formats) % get_metavar(action.nargs)
    return result

所以,使用您的 Meta 标签:
In [261]: x = Meta(['one', 'two'])
In [262]: x
Out[262]: <__main__.Meta at 0x7f36980f65c0>
In [263]: x = (x,)*2
In [264]: x
Out[264]: (<__main__.Meta at 0x7f36980f65c0>, <__main__.Meta at 0x7f36980f65c0>)
In [265]: '%s %s'%x
Out[265]: 'one two'

使用元组占位符:
In [266]: '%s %s'%('one','two')
Out[266]: 'one two'

和一个字符串相关
In [267]: '%s %s'%(('one two',)*2)
Out[267]: 'one two one two'

感谢您的解释,我的类确实能够正常工作,这一点并不明显。这也解释了为什么元组可以工作,而其他可迭代对象如列表则不行。 - Thibault D.

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