链接装饰器被定义为类?

时间:2012-03-19 19:21:08

标签: python decorator

为了学习,我试图链接由类定义的装饰器。我读了this question about decorators,它有很多关于用函数链接它们的好信息。它们也链接到documentation,但我试图找出更简单的例子。

基本上,我试图使用类来模仿类似的行为。这是我的第一个装饰器定义,它完美地运行。

class square_result(object):
    def __init__(self, f):
        pass

def __call__(self, x, y):
        return (x+y)**2

@square_result
def add_two_numbers(x, y):
    return x + y

print(add_two_numbers(2,5)) #Outputs 49, as expected

然后,我添加另一个装饰器来创建这段代码片段:

class square_result(object):
    def __init__(self, f):
        pass

    def __call__(self, x, y):
        return (x+y)**2

class append_abc(object):
    def __init__(self, f):
        pass

    def __call__(self, *args):
        return str(*args) + "abc"

@append_abc
@square_result
def add_two_numbers(x, y):
    return x + y

print(add_two_numbers(2,5))
#Ideally, this should print "49abc" but prints "(2,5)abc" instead

这样做的正确方法是什么?我想我想要做的是创建一个类的形式的装饰器,它接受它所装饰的函数的输出(在这种情况下是square_result)并将"abc"附加到它上面。

我知道当我在我的代码中添加一个装饰器时,会编译add_two_numbers()函数,并将该函数对象传递给square_result类,它会创建类似函数的对象。替换原始add_two_numbers()。但是,我不确定如何将其链接起来。

2 个答案:

答案 0 :(得分:2)

这样做你想要的:

class square_result(object):
    def __init__(self, f):
        pass

    def __call__(self, x, y):
        return (x+y)**2

class append_abc(object):
    def __init__(self, f):
        self.f = f

    def __call__(self, *args):
        return str(self.f(*args)) + "abc"

@append_abc
@square_result
def add_two_numbers(x, y):
    return x + y

print(add_two_numbers(2,5))

如果你想在装饰器的结果中使用它的输出,你需要实际在装饰器中运行内部函数

我没有编辑你的第一个装饰器,因为它可以做你想要的,但实际上它并没有用作装饰器。由于它的输出与它正在装饰的功能没有任何关系,所以它只是取代了这个功能。如果你想用该类替换该函数,那么这样做的方法是

class square_result(object):
    def __call__(self, x, y):
        return (x+y)**2

# this has no effect at all after the reassignment    
def add_two_numbers(x, y):
    return x + y

add_two_numbers = square_result()

PEP8还建议使用CamelCase作为您的班级名称(SquareResult)。

答案 1 :(得分:1)

square_result不会“装饰”add_two_numbers结果,而是覆盖它(执行添加以及平方)。它应该以与append_abc相同的方式处理装饰函数,方法是存储它,然后在自己的实现中使用装饰函数。因此:

class square_result(object):
    def __init__(self, f):
        self.function = f

    def __call__(self, *args):
        return self.function(*args)**2

class append_abc(object):
    def __init__(self, f):
        self.function = f

    def __call__(self, *args):
        return str(self.function(*args)) + "abc"

@append_abc
@square_result
def add_two_numbers(x, y):
    return x + y

print(add_two_numbers(2,5))