将关键字参数传递给类方法装饰器

时间:2010-03-12 05:48:31

标签: python decorator

我有一个类,它有一个output()方法,它返回一个matplotlib图实例。我有一个我写的装饰器,它接受了fig实例并将其转换为Django响应对象。

我的装饰师看起来像这样:

class plot_svg(object):
    def __init__(self, view):
        self.view = view

    def __call__(self, *args, **kwargs):
        print args, kwargs
        fig = self.view(*args, **kwargs)
        canvas=FigureCanvas(fig)
        response=HttpResponse(content_type='image/svg+xml')
        canvas.print_svg(response)
        return response

这就是它的使用方式:

def as_avg(self):
    return plot_svg(self.output)()

我这样做而不是使用“@”语法的唯一原因是因为当我使用“@”时:

@plot_svg
def as_svg(self):
    return self.output()

我收到此错误:

as_svg() takes exactly 1 argument (0 given)

我试图通过将其置于“@”语法中来“修复”此问题,但我无法弄清楚如何使其正常工作。我认为它与self没有被传递到它应该的地方有关...

2 个答案:

答案 0 :(得分:6)

正确:当您使用类而不是使用函数进行装饰时,您必须使其成为描述符(至少给它一个__get__方法)以获得“自动自我”。最简单的是用函数装饰:

def plot_svg(view):

    def wrapper(*args, **kwargs):
        print args, kwargs
        fig = view(*args, **kwargs)
        canvas = FigureCanvas(fig)
        response = HttpResponse(content_type='image/svg+xml')
        canvas.print_svg(response)
        return response

    return wrapper

背景:函数“成为方法”的原因(在类中定义并通过attribute-get表示法在其实例上访问),换句话说,这些函数可以获得自动self的原因是它们是描述符 - 函数类型有__get__

一个类没有__get__方法 - 除非您明确添加一个。那么为什么不用功能来装饰,如上例所示呢?通过这种方式,您可以自动获得良好的__get__函数 - 并且如您所见,嵌套函数“lexical closure”属性根本不会产生任何问题(实际上,它简化了事情 - 嵌套函数调用{{ 1}},而不是view如果self.view可能意味着您的装饰器类的实例或者您正在装饰的方法的实例,那么这可能会相当混乱。 ..! - 。)

答案 1 :(得分:1)

好的,似乎有几个问题。

首先,一些语法。你得到“只需一个参数”的错误,因为 你的装饰者@plot_svg期待一个参数(一个视图)。还有其他语法错误。

其次,更重要的是,你想要编写一个函数而不是装饰器。装饰者破坏了您对一个概念的访问权限,只允许您访问组合 概念。你只想要一个像这样的新功能:

def as_svg(an_object):
    return django_response(an_object.output())

或者,我误解了你的问题,因为代码示例太少了。