【问题标题】:A decorator that returns multiple functions返回多个函数的装饰器
【发布时间】:2019-11-05 06:58:57
【问题描述】:

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

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

我希望现在能够从my_module 导入resample_8resample_16resample_32。我可以编写装饰器并让它返回一个函数列表,但是如何使这些函数在模块命名空间中可用?

【问题讨论】:

  • 之后resample_8,resample_16,resample_32=resample 算不算?
  • 现在装饰器就是这样工作的。看看the source code for anosql,一个从 SQL 代码动态创建函数的库,以获得灵感。或者看看functools.partial()
  • (但是为什么你需要一个名为 resample_8() 的函数?它怎么比 resample(8) 更好?IMO 后者看起来更容易使用。很有可能这是一个 XY problem。 )

标签: python python-decorators


【解决方案1】:

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

编辑:K,也许这是一个 lil 有点偷偷摸摸。不要在没有监督 Pythonista 的情况下在家尝试这个。 martineau

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

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

functools.partial 是制作偏函数的好方法。这基本上是一个“半完成”的函数调用。创建一个偏函数让它记住参数和关键字参数,调用该偏函数将调用带有参数和关键字参数的原始函数。阅读更多关于它的信息here

这是你想要的装饰器,但我强烈建议不要使用它。

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

我的替代方法是使用 Chris 所说的从装饰器创建许多功能不利于维护和清晰。

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

from functools import partial

# assign your function things here
resample_8 = partial(resample, new_size=8)
# repeat for other names

【讨论】:

  • 这看起来不错!我在这里遇到的唯一问题是globals 获取定义装饰器的模块的符号表,而不是运行它的位置,因此导入装饰器将不起作用。就像你和@Chris 说的那样,我可能会避开这个。
  • 啊,好像我跳过了“导入装饰器”部分。这会更难,但现在看起来已经不重要了。
  • IMO 在装饰器中分配给全局字典一种偷偷摸摸的 hack(如果它在这种情况下有效)。
  • 您可以通过堆栈检查访问调用者的全局变量,避免导入问题,但不能避免诸如“如果我尝试在非全局命名空间中使用此装饰器会怎样”或“多少维护和可读性令人头疼的是这件事将在 6 个月后完成”。
  • @user2357112 的评论应添加到未来读者的答案中。
猜你喜欢
  • 2020-04-28
  • 1970-01-01
  • 1970-01-01
  • 2021-06-24
  • 2020-12-04
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
  • 2018-04-02
相关资源
最近更新 更多