Передача аргументов ключевых слов в декоратор метода класса - PullRequest
6 голосов
/ 12 марта 2010

У меня есть класс, у которого есть метод output (), который возвращает экземпляр Figure 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 ]

5 голосов
/ 12 марта 2010

Справа: когда вы декорируете классом, а не функцией, вы должны сделать его дескриптором (по крайней мере, назначьте ему метод __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

Фон: причина, по которой функции «становятся методами» (если они определены в классе и доступны в его экземпляре с помощью записи атрибута-получения), другими словами, причина, по которой такие функции могут получить свои автоматические self, заключается в том, что они re дескрипторы - тип функции имеет __get__.

У класса нет __get__ метода - если вы не добавили его явно. Так почему бы просто не украсить ее функцией, как в примере выше? Таким образом, вы автоматически получаете симпатичные __get__ функций - и, как вы видите, свойство «лексическое замыкание» вложенных функций вообще не создает никаких проблем (на самом деле, это упрощает вещи - вызовы вложенных функций view, не self.view, что может быть довольно запутанным, если self может означать либо экземпляр вашего класса декоратора, либо экземпляр класса , метод которого вы украшаете ...! -).

1 голос
/ 12 марта 2010

ОК, похоже, есть несколько проблем.

Сначала немного синтаксиса. Вы получаете ошибку «принимает ровно один аргумент», потому что ваш декоратор @plot_svg ожидает один параметр (представление). Есть и другие синтаксические ошибки.

Во-вторых, и что более важно, вы хотите написать функцию вместо декоратора. Декоратор разрушает ваш доступ к одной концепции и дает вам доступ только к концепция. Вам просто нужна новая функция, подобная этой:

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

С другой стороны, я неправильно понимаю ваш вопрос из-за слишком маленького примера кода.

...