Python Decorators запускаются до того, как вызывается функция, которую он украшает? - PullRequest
9 голосов
/ 04 декабря 2008

Например,

def get_booking(f=None):
    print "Calling get_booking Decorator"
    def wrapper(request, **kwargs):
        booking = _get_booking_from_session(request)
        if booking == None:
            # we don't have a booking in our session.
            return HttpRedirect('/')
        else:
            return f(request=request, booking=booking, **kwargs)
    return wrapper

@get_booking
def do_stuff(request, booking):
    # do stuff here

У меня проблема в том, что декоратор @get_booking вызывается еще до того, как я вызвал функцию, которую я декорирую.

Выход при запуске:

Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
[26/Oct/2008 19:54:04] "GET /onlinebooking/?id=1,2 HTTP/1.1" 302 0
[26/Oct/2008 19:54:05] "GET /onlinebooking/ HTTP/1.1" 200 2300
[26/Oct/2008 19:54:05] "GET /site-media/css/style.css HTTP/1.1" 200 800
[26/Oct/2008 19:54:05] "GET /site-media/css/jquery-ui-themeroller.css HTTP/1.1" 200 25492

Я даже не вызывал функцию, которая оформлена в этот момент.

Я только начинаю с декораторами, так что, может быть, я что-то упустил. Любая помощь?

Ответы [ 4 ]

32 голосов
/ 04 декабря 2008

Я считаю, что декораторы Python - это просто синтаксический сахар.

@foo
def bar ():
    pass

- это то же самое, что и

def bar ():
    pass
bar = foo(bar)

Как видите, foo вызывается, хотя bar не вызывается. Вот почему вы видите результат работы вашей функции декоратора. Ваш вывод должен содержать одну строку для каждой функции, к которой вы применили декоратор.

2 голосов
/ 04 декабря 2008

Поскольку вы начинаете с декораторов, я думаю, что их чтение будет полезно, так что вы заранее знаете подводные камни и обходные пути.

Вот две ссылки на предыдущие обсуждения декораторов.

Python декоратор заставляет функцию забыть, что она принадлежит классу Что делает functools.wraps?

Кроме того, во второй ссылке упоминается «functools» модуль для функций высшего порядка, которые действуют или возвращают другие функции. Рекомендуется использовать functools.wraps, поскольку он сохраняет строку документа исходной функции (оформленной).

Другая проблема заключалась в неправильных сигнатурах методов при создании автоматических документов для моего проекта. но есть обходной путь: Сохранение подписей декорированных функций

Надеюсь, это поможет.

0 голосов
/ 04 декабря 2008

Python-декораторы - это функции, применяемые к функции для ее преобразования:

@my_decorator
def function (): ...

похоже на это:

def function():...
function = my_decorator(function)

То, что вы хотите сделать, это:

def get_booking(f=None):
    def wrapper(request, **kwargs):
        print "Calling get_booking Decorator"
        booking = _get_booking_from_session(request)
        if booking == None:
            # we don't have a booking in our session.
            return HttpRedirect('/')
        else:
            return f(request=request, booking=booking, **kwargs)
    return wrapper
0 голосов
/ 04 декабря 2008

Декоратор вызывается, как только определяется декорированная функция. Это эквивалентно написанию чего-то вроде этого:

def __do_stuff(...):
    ...

do_stuff = get_booking(__do_stuff)
...