Python装饰器在它正在装饰的函数之前运行吗?

时间:2008-12-04 17:13:32

标签: python django decorator

举个例子,

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 个答案:

答案 0 :(得分:32)

我相信python装饰器只是语法糖。

@foo
def bar ():
    pass

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

如您所见,即使未调用 bar ,也会调用 foo 。这就是你看到装饰器功能的输出的原因。对于应用装饰器的每个函数,您的输出应该包含一行。

答案 1 :(得分:2)

由于你是从装饰者开始的,我认为阅读这些装置会很有帮助,所以你事先就知道了陷阱和变通方法。

以下是关于装饰器的早期讨论的两个链接。

Python decorator makes function forget that it belongs to a class What does functools.wraps do?

此外,第二个链接提到'functools'是一个用于高阶函数的模块,它可以作用于或返回其他函数。建议使用functools.wraps,因为它保留了原始函数的doc字符串(装饰一个)。

另一个问题是在为我的项目生成自动文档时错误的方法签名。 但有一个解决方法: Preserving signatures of decorated functions

希望这有帮助。

答案 2 :(得分:0)

定义修饰函数后立即调用装饰器。这相当于写下这样的东西:

def __do_stuff(...):
    ...

do_stuff = get_booking(__do_stuff)

答案 3 :(得分:0)

python decorators是应用于函数的函数,用于转换它:

@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