是否可以在Python Click中动态生成命令

时间:2018-11-05 02:25:26

标签: python click

我正在尝试从配置文件生成click命令。本质上,这种模式:

import click

@click.group()
def main():
    pass

commands = ['foo', 'bar', 'baz']
for c in commands:
    def _f():
        print("I am the '{}' command".format(c))
    _f = main.command(name=c)(_f)

if __name__ == '__main__':
    main()

--help文字看起来不错:

Usage: test_click.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  bar
  baz
  foo

但是所有命令似乎都路由到最后一个生成的命令:

$ ./test_click.py foo
I am the 'baz' command
$ ./test_click.py bar
I am the 'baz' command
$ ./test_click.py baz
I am the 'baz' command

我实际上要尝试的是什么吗?

2 个答案:

答案 0 :(得分:2)

您应该使用为命令创建另一个功能的函数,此处为示例

import click

commands = ['foo', 'bar', 'baz']


@click.group()
def main():
    pass


def create_func(val):
    def f():
        print("I am the '{}' command".format(val))
    return f


for c in commands:
    main.command(name=c)(create_func(c))

if __name__ == '__main__':
    main()

答案 1 :(得分:1)

问题在于python的功能范围。创建函数_f时,它使用的c的作用域比函数大。因此,在调用该函数时将不会保留它。 (_f在您调用main时被调用)

在您调用main时,循环完成,并且c将始终保存循环的最后一个值-baz

解决方案是使用自己的作用域将值c附加到函数上。

import click

@click.group()
def main():
    pass

commands = ['foo', 'bar', 'baz']

def bind_function(name, c):
    def func():
        print("I am the '{}' command".format(c))

    func.__name__ = name
    return func

for c in commands:
    f = bind_function('_f', c)
    _f = main.command(name=c)(f)

if __name__ == '__main__':
    main()

bind_function还允许您根据需要用不同的方式命名函数。