首页 > 解决方案 > 将返回自我的函数装饰器?

问题描述

我必须遵循将使用从类变量派生的可链接方法创建对象的类。由于这段代码非常重复,我的挑战是制作一个可以应用于方法的装饰器ab并且c. 我面临的问题是我似乎无法找到一种方法来构造一个将返回实例 ( 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()

标签: pythoninstancedecoratorpython-decoratorsself

解决方案


诀窍是将函数的参数存储为调用链的一部分。最简单的方法是使用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

推荐阅读