python - 使用一个类同时作为装饰器和装饰器工厂进行操作

标签 python python-3.x python-decorators

考虑以下装饰器函数,它要么返回一个装饰函数,要么返回一个参数化的装饰函数:

from functools import wraps, partial, update_wrapper
from inspect import signature

def wrapit(func=None, *, verb='calling'):
    if func is None:  # return a decoratOR
        return partial(wrapit, verb=verb)
    else:  # return a decoratED
        @wraps(func)
        def _func(*args, **kwargs):
            print(f'{verb} {func.__name__} with {args} and {kwargs}')
            return func(*args, **kwargs)
        return _func

演示:

>>> f = lambda x, y=1: x + y
>>> ff = wrapit(verb='launching')(f)
>>> assert ff(10) == 11
launching <lambda> with (10,) and {}
>>> assert signature(ff) == signature(f)
>>>
>>> # but can also use it as a "decorator factory"
>>> @wrapit(verb='calling')
... def f(x, y=1):
...     return x + y
...
>>> assert ff(10) == 11
launching <lambda> with (10,) and {}
>>> assert signature(ff) == signature(f)

类的形式可能看起来像这样:

class Wrapit:
    def __init__(self, func, verb='calling'):
        self.func, self.verb = func, verb
        update_wrapper(self, func)

    def __call__(self, *args, **kwargs):
        print(f'{self.verb} {self.func.__name__} with {args} and {kwargs}')
        return self.func(*args, **kwargs)

但是我们如何让类能够在功能形式具有的“装饰器工厂”模式下运行(由 if func is None: return partial... 实现) 我们如何将这个技巧集成到装饰器类中?

最佳答案

正如评论中所建议的那样,您可以使用 __new__ 方法执行此操作:

class Wrapit:
    def __new__(cls, func=None, *, verb='calling'):
        if func is None:
            return partial(cls,verb=verb)
        self = super().__new__(cls)
        self.func, self.verb = func, verb
        update_wrapper(self, func)
        return self

    def __call__(self, *args, **kwargs):
        print(f'{self.verb} {self.func.__name__} with {args} and {kwargs}')
        return self.func(*args, **kwargs)

__new__ 方法在您尝试实例化一个类时被调用,并且该方法的返回值用作尝试实例化的结果——即使它不是该类的实例!

关于python - 使用一个类同时作为装饰器和装饰器工厂进行操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62379216/

相关文章:

Python - eyeD3 Lame 标签 CRC 检查失败

python - IDLE 如何运行 .py 模块?

Python 装饰器强制显式传递参数

python - 使用装饰器为递归函数计时

python - 从 stdout 或 stderr 获取子进程的消息

python - python装饰器中的foo=bar(foo)和something=bar(foo)有什么区别?

python - 将 Python numpy 数组写入 .mat 文件

python - 无法让子进程结束/退出

python - 计算字母在单词中出现的次数,并将其以以下格式:

Python 循环获取请求