函数装饰器会返回自我吗?

时间:2019-02-14 15:52:04

标签: python instance decorator python-decorators self

我必须遵循以下类,该类将使对象具有可从类变量派生的可链接方法。由于此代码是非常重复的代码,因此我面临的挑战是制作一个可以应用于方法abc的装饰器。我面临的问题是,我似乎找不到找到构造返回该实例(self)的包装器的方法。有没有更好的方法来构造它?

class Test:

    def __init__(self, a, b, c):
        self._a = a
        self._b = b
        self._c = c

        self.call_chain = []


    def a(self, truth):
        def func():
            return self._a == truth
        self.call_chain.append(func)
        return self


    def b(self, truth):
        def func():
            return self._b == truth
        self.call_chain.append(func)
        return self


    def c(self, val):
        def func():
            return self._c == val
        self.call_chain.append(func)
        return self


    def evaluate(self):
        try:
            for f in self.call_chain:
                if f() == False:
                    raise ValueError('False encountered')
        except ValueError:
            self.call_chain.clear()
            return False 
        self.call_chain.clear()
        return True

它的工作方式如下:

c = Test(True, False, 13)
c.a(True).b(False).c(13).evaluate()

1 个答案:

答案 0 :(得分:1)

技巧是将参数存储到函数中,作为调用链的一部分。最简单的方法是使用functools.partial个对象。

from functools import wraps, partial

def chain(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        suspended = partial(func, self, *args, **kwargs)
        self.call_chain.append(suspended)
        return self
    return wrapper

class Test:
    def __init__(self, a, b, c):
        self.call_chain = []
        self._a = a
        self._b = b
        self._c = c
    @chain
    def a(self, val):
        return self._a == val
    @chain
    def b(self, val):
        return self._b == val
    @chain
    def c(self, val):
        return self._c == val
    def evaluate(self):
        try:
            for f in self.call_chain:
                if f() == False:
                    raise ValueError('False encountered')
        except ValueError:
            self.call_chain.clear()
            return False 
        self.call_chain.clear()
        return True

c = Test(True, False, 13)
c.a(True).b(False).c(13).evaluate()  # True
c.a(True).b(False).c(11).evaluate()  # False