如何将几个参数列表传递给@ click.option

dow*_*roy 11 python parameters command-line python-click

我想通过命令行使用这种参数调用python脚本(列表可以是任何大小,例如3):

python test.py --option1 ["o11", "o12", "o13"] --option2 ["o21", "o22", "o23"]
Run Code Online (Sandbox Code Playgroud)

使用点击.从文档中,我们无法在任何地方声明我们可以使用列表作为@ click.option的参数

当我尝试这样做时:

#!/usr/bin/env python
import click

@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', default=[])
def do_stuff(option):

    return

# do stuff
if __name__ == '__main__':
    do_stuff()
Run Code Online (Sandbox Code Playgroud)

在我的test.py,通过从命令行调用它:

python test.py --option ["some option", "some option 2"]
Run Code Online (Sandbox Code Playgroud)

我收到一个错误:

错误:得到意外的额外参数(某些选项2))

我不能真正使用可变参数,因为每个命令只允许1个可变参数(http://click.pocoo.org/5/arguments/#variadic-arguments)

因此,如果有人能指出我正确的方向(最好使用点击),我将非常感激.

Jar*_*rno 34

如果您不坚持传递看起来像列表的内容,而只是想传递多个可变参数,则可以使用该multiple选项。

点击文档

@click.command()
@click.option('--message', '-m', multiple=True)
def commit(message):
    click.echo('\n'.join(message))
Run Code Online (Sandbox Code Playgroud)
$ commit -m foo -m bar
foo
bar
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,这似乎是更明智的答案,它按预期使用点击,而不会不必要地覆盖 (3认同)

Ste*_*uch 17

如果通过使用自定义选项类将列表格式化为python列表的字符串文字,则可以强制单击以获取多个列表参数:

自定义类:

import click
import ast

class PythonLiteralOption(click.Option):

    def type_cast_value(self, ctx, value):
        try:
            return ast.literal_eval(value)
        except:
            raise click.BadParameter(value)
Run Code Online (Sandbox Code Playgroud)

该类将使用Python的抽象语法树模块将参数解析为python文字.

自定义类用法:

要使用自定义类,请将cls参数传递给@click.option()装饰器,如:

@click.option('--option1', cls=PythonLiteralOption, default=[])
Run Code Online (Sandbox Code Playgroud)

这是如何运作的?

这是有效的,因为click是一个设计良好的OO框架.该@click.option()装饰通常实例化一个click.Option对象,但允许这种行为是对超缠身cls参数.因此,从click.Option我们自己的班级继承并过度使用所需的方法是相对容易的事情.

在这种情况下,我们过度骑click.Option.type_cast_value(),然后调用ast.literal_eval()解析列表.

测试代码:

@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option1', cls=PythonLiteralOption, default=[])
@click.option('--option2', cls=PythonLiteralOption, default=[])
def cli(option1, option2):
    click.echo("Option 1, type: {}  value: {}".format(
        type(option1), option1))
    click.echo("Option 2, type: {}  value: {}".format(
        type(option2), option2))

# do stuff
if __name__ == '__main__':
    import shlex
    cli(shlex.split(
        '''--option1 '["o11", "o12", "o13"]' 
        --option2 '["o21", "o22", "o23"]' '''))
Run Code Online (Sandbox Code Playgroud)

检测结果:

Option 1, type: <type 'list'>  value: ['o11', 'o12', 'o13']
Option 2, type: <type 'list'>  value: ['o21', 'o22', 'o23']
Run Code Online (Sandbox Code Playgroud)

  • 这个技巧很好,我只是有点挑剔:默认空列表值周围需要引号,例如 **@click.option('--option1', cls=PythonLiteralOption, default='[]')** . 否则省略该选项会导致 **AttributeError: 'list' object has no attribute 'encode'**。 (3认同)