点击装饰器可以在非主要功能上很好地工作吗?

Can click decorators work nicely on non-main functions?

我希望有一些 CLI 选项可以在共享公共库文件的两个程序之间重复使用。目前,每个文件的结构如下:

from .shared import G

@click.command()
@click.option("--thing1", …)
@click.optoin("--thing2", …)
…
def main(**kwargs):
    g = G()
    g.do_your_thing()

我想做的是将所有内容移动到 G__init__G 的子 class。

class G:
    @click.command()
    @click.option("--thing1")
    def __init__(**kwargs):
        pass

class G6(G):
    @click.command()
    @click.option("--specific-flag")
    def __init__(**kwargs):
        super().__init__(**kwargs)
        if kwargs.get("--specific-flag"):
             do_something()
        self.seven = 7

但是,当我尝试这样做时,出现以下错误。

Usage: something.py [OPTIONS]
Try 'something.py --help' for help.

Error: no such option: --thing1

我进行此重构的主要目标是通过将共享装饰器移动到库中来消除装饰每个程序的 main 函数的大量重复代码。

如果可能的话,是否也可以使用子 class 的选项装饰器来取代基础 class 上的相同装饰器?我假设答案是肯定的。


编辑

根据下面的答案,我的程序现在可以使用类似于以下代码段的结构:

_common_options = [
    click.option(…), click.option(…), …
]

def common_options(func):
    for option in _common_options:
        func = option(func)
    return func

class G:
    def __init__(**kwargs):
        print(kwargs)

@click.command()
@common_options
@click.option("--specific-option", …)
def main(**kwargs):
    f = G(**kwargs)

我最初尝试的问题是将所有 @click.whatever 东西作为 __init__ 的装饰器,而不是装饰 main 并将 **kwargs 传递给 __init__.

我之前所做的是创建要应用于命令或组的选项列表。例如:


_global_options = [
    click.option('-v', '--verbose', count=True, default=0, help='Verbose output.'),
    click.option('-n', '--dry-run', is_flag=True, default=False, help='Dry-run mode.')
]


def common_options(func):
    for option in reversed(_global_options):
        func = option(func)
    return func

这些将被这样应用:

click.group(name='my_group')
@common_options
def my_group(*args, **kwargs):
    pass

装饰器似乎与 Click 配合得很好。 这有帮助吗?