当@click.option用于将命令行参数传递给函数时,如何返回值



我正在尝试使用click python包将命令行参数传递给函数。官方文件中的例子如所述。但文档中没有提到如何返回值。文档中没有一个函数返回值,所以我不知道如何执行此操作。

文档中给出的示例:

import click
@click.command()
@click.option('--count', default=3, help='Number of greetings.')
def hello(count):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello')
if __name__ == '__main__':
    hello()

我想做的事:

import click
@click.command()
@click.option('--count', default=3, help='Number of greetings.')
def hello(count):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello')
    return "hello hi"
if __name__ == '__main__':
    print(hello())

"hello-hi"不会作为控制台上的输出返回。有人能告诉我如何做到这一点吗?

不幸的是,您试图做的事情没有意义。命令行程序可以有退出代码,但这只是一个小整数;它们不能返回文本或任意Python对象。

这些整数的含义有一个准标准;简单版本为0表示成功,1表示大多数错误,2表示无效的命令行参数。click试图使您的函数成为一个好的命令行公民,因此当您退出函数时,它会用适当的数字调用sys.exit(如果您是return,则为0;如果您是raise,则为1;如果它未能解析您的参数,则为2)。

因此,无论您使用return做什么都没有效果,无论您尝试使用顶级返回值做什么都不会运行。

当程序需要"返回"文本时,通常会将其打印到标准输出,这正是click.echo的作用。

默认情况下,单击会将程序转换为命令行程序,即执行click命令并返回代码退出。因此,您的程序执行hello并完成:

import click
@click.command()
@click.option('--count', default=3, help='Number of greetings.')
def hello(count):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello')
    return "hello hi"
if __name__ == '__main__':
    print(hello())

它打印:

Hello
Hello
Hello

您可以通过传递参数standalone_mode=False(单击API命令)来更改此行为:

import click
@click.command()
@click.option('--count', default=3, help='Number of greetings.')    
def hello(count):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello')
    return "hello hi"
if __name__ == '__main__':
    print(hello(standalone_mode=False))

它打印:

Hello
Hello
Hello
hello hi

在浏览了click的源代码/引用后,我偶然发现了BaseCommand的main()方法,该方法采用参数standalone_mode,允许您在禁用时返回值(默认情况下为True)。希望这对将来的人有所帮助。

设置代码:

import sys
import click
@click.group(invoke_without_command=True)
@click.option('--option1')
@click.argument('arg1')
def main(option1, arg1):
    class SpecialObject():
        def __init__(self, option, arg):
            self.option = option
            self.arg = arg
        def __repr__(self):
            return str(self.option)+str(self.arg)
    return SpecialObject(option1, arg1)
@main.command()
def subcmd():
    return [4,5,6]

测试代码:

if __name__ == "__main__":
    commands = (
        ["--help"], 
        ["arg_val",],
        ["--option1","option1_val","arg1_val"],
        ["arg_val","subcmd"],
        ["arg_val","subcmd", "--help",], 
    )
    print(f'Click Version: {click.__version__}')
    print(f'Python Version: {sys.version}')
    for cmd in commands:
        print('-----------')
        print(f'Starting cmd:{cmd}')
        ret_val = main.main(cmd, standalone_mode=False)
        print(f"Returned: {type(ret_val)}, {ret_val}n"

输出:

$ python __main__.py
Click Version: 7.1.2
Python Version: 3.9.1 (default, Dec 11 2020, 09:29:25) [MSC v.1916 64 bit (AMD64)]
-----------
Starting cmd:['--help']
Usage: __main__.py [OPTIONS] ARG1 COMMAND [ARGS]...
Options:
  --option1 TEXT
  --help          Show this message and exit.
Commands:
  subcmd
Returned: <class 'int'>, 0
-----------
Starting cmd:['arg_val']
Returned: <class '__main__.main.<locals>.SpecialObject'>, Nonearg_val
-----------
Starting cmd:['--option1', 'option1_val', 'arg1_val']
Returned: <class '__main__.main.<locals>.SpecialObject'>, option1_valarg1_val
-----------
Starting cmd:['arg_val', 'subcmd']
Returned: <class 'list'>, [4, 5, 6]
-----------
Starting cmd:['arg_val', 'subcmd', '--help']
Usage: __main__.py subcmd [OPTIONS]
Options:
  --help  Show this message and exit.
Returned: <class 'int'>, 0

您必须告诉click使用click.echo()打印到stdout。下面是一个使用问题中的代码的工作示例(不必像其他人提到的那样关心退出代码):

import click

@click.command()
@click.option('--count', default=3, help='Number of greetings.')
def hello(count):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello')
    return click.echo("hello hi")
if __name__ == '__main__':
    hello()

请在此处查看点击文档,也可以在此处查看此答案

# Main Runtime call at bottom of code
hello(standalone_mode=False)
# or e.g
main(standalone_mode=False)

显然,这个click包使您的hello()函数永远不会返回。所以印刷永远不会发生。如果我是你,我不会使用这个非直观的包,而是使用argparse,它非常擅长Python中的命令行处理(在我看来,它是所有语言中最好的之一)。

以下是使用argparse的代码的工作版本。它与Python(任何2.7或更高版本)开箱即用,而且很容易理解。

def hello(count):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        print('Hello')
    return "hello hi"
if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--count', default=3, type=int, help='Number of greetings.')
    args = parser.parse_args()
    print(hello(args.count))

最新更新