如何在Python中编写装饰器类?

时间:2017-06-09 21:35:38

标签: python python-3.x class decorator python-decorators

不是类装饰器,而是装饰器类。

我可以编写一个装饰器函数,它工作正常,但是当我尝试将它作为一个类实现(主要是从嵌套中解决)时,我会陷入自拍状态。这是一个最小的工作示例:

注意装饰器与括号一起使用,如@DecoratorClass()而不是@DecoratorClass。这会产生很大的不同。

def decorator_function():
    def decorator(fcn):
        def wrapper(self, *args):
            print('decorator_function wrapper self:', self)
            print('decorator_function wrapper args:', args)
            return fcn(self, *args)
        return wrapper
    return decorator


class DecoratorClass:
    def __init__(self):
        self.fcn = None
    def __call__(self, fcn):
        self.fcn = fcn
        return self.wrapper
    def wrapper(self, *args):
        print('DecoratorClass wrapper self:', self)
        print('DecoratorClass wrapper args:', args)
        return self.fcn(*args)


class A:
    @decorator_function()
    def x(self, *args):
        print('A x self:', self)
        print('A x args:', args)
        return 42

    @DecoratorClass()
    def y(self, *args):
        print('A y self:', self)
        print('A y args:', args)
        return 43

a = A()
a.x(1, 2)
a.y(1, 2)

这是输出。

decorator_function wrapper self: <mytests.debugme.A object at 0x7fa540d315f8>
decorator_function wrapper args: (1, 2)
A x self: <mytests.debugme.A object at 0x7fa540d315f8>
A x args: (1, 2)
DecoratorClass wrapper self: <mytests.debugme.DecoratorClass object at 0x7fa540d31208>
DecoratorClass wrapper args: (1, 2)
A y self: 1
A y args: (2,)

如您所见,基于类的方法失去了对a的引用。为了澄清,我希望a.y(1,2)的结果与a.x(1,2)相同。

更新@Martijn Pieters

class DecoratorClass:
    def __init__(self):
        self.fcn = None
    def __call__(self, fcn):
        self.fcn = fcn
        return self.wrapper
    def __get__(self, obj, objtype):
        """Support instance methods."""
        import functools
        return functools.partial(self.__call__, obj)
    def wrapper(self, *args):
        print('DecoratorClass wrapper self:', self)
        print('DecoratorClass wrapper args:', args)
        return self.fcn(*args)
a = A()
a.y(1, 2)

输出:

DecoratorClass wrapper self: <mytests.debugme.DecoratorClass object at 0x7fa540d31048>
DecoratorClass wrapper args: (1, 2)
A y self: 1
A y args: (2,)

IOW:标记的重复问题没有可行的答案。

0 个答案:

没有答案