装饰器在调用它装饰的函数之前运行?

Posted

技术标签:

【中文标题】装饰器在调用它装饰的函数之前运行?【英文标题】:Decorators run before function it is decorating is called? 【发布时间】:2010-09-25 09:04:01 【问题描述】:

举个例子:

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 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
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

此时我什至还没有调用装饰过的函数。

我刚刚开始使用装饰器,所以也许我遗漏了一些东西。

【问题讨论】:

直接回答问题标题,装饰器是否在被装饰函数之前运行?。不,声明函数时它不会运行。它在函数被调用时运行。我希望这会有所帮助。 【参考方案1】:

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

@foo
def bar ():
    pass

是一样的
def bar ():
    pass
bar = foo(bar)

如您所见,虽然 bar 没有被调用,但 foo 正在被调用。这就是为什么您会看到装饰器函数的输出。你的输出应该包含你应用装饰器的每个函数的一行。

【讨论】:

【参考方案2】:

一旦定义了装饰函数,就会调用装饰器。相当于这样写:

def __do_stuff(...):
    ...

do_stuff = get_booking(__do_stuff)

【讨论】:

【参考方案3】:

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

【讨论】:

在装饰器中为目标函数提供默认值有什么好处? 特别是因为它从未检查过 None。 我真的不知道他的目的是什么,我以为是为了重定向。【参考方案4】:

由于您是从装饰器开始的,我认为阅读这些内容会有所帮助,以便您提前了解陷阱和解决方法。

这里有两个链接指向之前关于装饰器的讨论。

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

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

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

希望这会有所帮助。

【讨论】:

以上是关于装饰器在调用它装饰的函数之前运行?的主要内容,如果未能解决你的问题,请参考以下文章

简单理解装饰器在Python里面的作用

装饰器

python装饰器在接口自动化测试中的应用

二装饰器

一文带你了解 Python 中的装饰器

叠加装饰器迭代器