一个返回多个函数的装饰器

Kyl*_*yle 5 python python-decorators

我想编写一个装饰器,将多个函数放入模块命名空间。考虑以下模块:

# my_module.py


from scipy import signal


@desired_decorator(new_size=(8, 16, 32))
def resample(x, new_size):
    return signal.resample(x, new_size)
Run Code Online (Sandbox Code Playgroud)

我想现在可以进口resample_8resample_16以及resample_32my_module。我可以编写装饰器并让它返回一个函数列表,但是如何使这些函数在模块命名空间中可用?

Gee*_*sit 4

由于您可以在不使用偷偷摸摸的黑客的情况下分配给全局字典,因此这几乎是可能的。(语法不错)

编辑:K,也许这有点偷偷摸摸。如果没有 Pythonista 的监督,请勿在家尝试此操作。马蒂诺

EDIT2:可以通过使用堆栈自省来获取调用者的全局变量,这可以避免导入问题,但在非全局命名空间中调用时它将不起作用,或者在 6 个月内消除您的困惑。用户2357112

globals()返回全局变量的字典。分配给它使用户可以导入这些函数

functools.partial是创建部分函数的好方法。这基本上是一个“半完成”的函数调用。创建部分函数使其记住参数和关键字参数,并且调用该部分函数将使用参数和关键字参数调用原始函数。在这里阅读更多相关信息。

这是您想要的装饰器,尽管我强烈建议不要使用它。

from functools import partial

def desired_decorator(**kwargs):
    # make sure there's only one keyword argument
    assert len(kwargs) == 1
    # unpack the single keyword and the values
    keyword, values = (*kwargs.items(),)[0]
    # this is the actual decorator that gets called
    def _make_variants(func):
        for value in values:
            # assign to the globals dictionary
            globals()[
                f"{func.__name__}_{value}"
            ] = partial(func, **{keyword: value})
        # keep the original function available
        return func
    return _make_variants
Run Code Online (Sandbox Code Playgroud)

我的替代方案是使用克里斯所说的,因为从装饰器创建许多功能不利于维护和清晰度。

这是我建议的代码,但如果您愿意,也可以使用上面的代码。

from functools import partial

# assign your function things here
resample_8 = partial(resample, new_size=8)
# repeat for other names
Run Code Online (Sandbox Code Playgroud)

  • 您可以通过堆栈检查访问调用者的全局变量,避免导入问题,但不能避免诸如“如果我尝试在非全局命名空间中使用此装饰器怎么办”或“这件事的维护和可读性有多么令人头痛”之类的问题6个月后”。 (2认同)