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

Python 将关键字参数传递给类方法装饰器,python,decorator,Python,Decorator,我有一个类,它有一个output()方法,返回matplotlib Figure实例。我编写了一个decorator,它将fig实例转换为Django响应对象 我的装饰师看起来像这样: class plot_svg(object): def __init__(self, view): self.view = view def __call__(self, *args, **kwargs): print args, kwargs f

我有一个类,它有一个output()方法,返回matplotlib Figure实例。我编写了一个decorator,它将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_svg(an_object):
    return django_response(an_object.output())
这就是它的使用方式:

def as_avg(self):
    return plot_svg(self.output)()
我使用这种方式而不是使用“@”语法的唯一原因是,当我使用“@”时:

我得到这个错误:

as_svg() takes exactly 1 argument (0 given)

我试图用“@”语法来“修复”这个问题,但我不知道如何让它工作。我认为这与
self
没有通过它应该通过的地方有关…

对:当你用一个类而不是函数来装饰时,你必须让它成为一个描述符(至少给它一个
\u get\u
方法)来获得“自动的self”。最简单的方法是用一个函数来装饰:

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
背景:函数“成为方法”的原因(当在类中定义并通过属性get表示法在其实例上访问时),换句话说,这些函数能够自动获得其
self
的原因是它们是描述符——函数类型有一个
\uu get\uu


类没有
\uuuu get\uuuu
方法——除非您显式添加一个方法。那么,为什么不像上面的例子那样,用一个函数来装饰呢?通过这种方式,您可以自动获得函数的nice
\uuuuuuuuuuuuuuuuuuuuuuuuuuu
——正如您所看到的,嵌套函数“lexical closure”属性根本不会带来任何问题(事实上,它简化了事情——嵌套函数调用的是
view
,而不是
self.view
,如果
self
可能意味着装饰器类的一个实例或您正在装饰其方法的类的一个实例…!-),那么这可能会让人相当困惑。

好的,似乎有两个问题

首先是一些语法。您会得到“只接受一个参数”错误,因为 您的装饰程序@plot_svg需要一个参数(视图)。还有其他语法错误

第二,也是更重要的一点,你想写一个函数而不是一个装饰器。装饰器破坏了你对一个概念的访问权,只给你对组合概念的访问权 概念。您只需要这样一个新函数:

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_svg(an_object):
    return django_response(an_object.output())

或者,由于代码示例太少,我误解了您的问题。

我被您的答案弄糊涂了。我原以为替换相当于预期的词汇替换。因此:@plot_svg(view=some_view)def some_func(some_args):…->(减去中间变量/绑定)def some_func(一些参数):…a_plot_instance=plot_svg.\u_init_(view=some_view)some_func=a_plot_instance.\u调用__(some_参数)你能澄清一下吗?我讨厌缺少注释格式。@charles.merriam:有注释格式。使用**表示粗体,使用*表示斜体,使用反勾(`)对于
code
等…您可能需要不时使用反斜杠…我对您的答案感到困惑。我原以为替换相当于预期的词汇替换。因此:
@plot\u svg(view=some\u view)
\n
定义一些函数(some参数):…
\n->(减去中间变量/绑定)\n
定义一些函数(一些参数):…
\n
a\u plot\u instance=plot\u svg.\uu init\uu(view=some\u view)
\n
some\u func=a\u plot\u instance.\uu调用(一些参数)
\n您能澄清一下吗?@charles.merriam:如果您不以@Alex Martelli开始评论,他将不会自动得到通知,而且他可能不会再讨论这个问题。@ChristopheD,我确实会收到关于我答案的评论的通知——您可能已经记住了“回复我的评论”。