使用一个类同时充当装饰器和装饰器工厂

问题描述 投票:0回答:1

考虑以下装饰器函数,该装饰器函数将返回装饰器函数或参数化的decorat 函数:

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)

但是我们如何使该类能够在功能形式具有的“ decorator factory”模式下运行(由if func is None: return partial...实现我们如何将这个技巧整合到装饰类中?

python python-3.x python-decorators
1个回答
0
投票

如注释中所建议,您可以使用__new__方法执行此操作:

class Wrapit:
    def __new__(cls, func=None, *, verb='calling'):
        if func is None:
            return partial(Wrapit,verb=verb)
        self = object.__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__方法在您尝试实例化一个类时都会被调用,并且该方法的返回值将用作尝试实例化的结果-即使它不是该类的实例!

© www.soinside.com 2019 - 2024. All rights reserved.