【问题标题】: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

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

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

【问题讨论】:

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

标签: python django decorator


【解决方案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

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2017-08-20
        • 1970-01-01
        • 2010-09-21
        • 1970-01-01
        • 2018-04-28
        • 2013-01-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多