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

7
我将尝试从配置文件中生成“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个回答

7
问题出在 Python 的函数作用域上。当您创建函数 _f 时,它使用的是比函数更高的作用域 c。因此,当您调用该函数时,它将不会保留该值。(_f 在调用主函数时被调用)。
当您调用 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()
< p > bind_function还允许您根据需要以不同的名称命名函数。


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()

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