【问题标题】:How to understand the calling sequence of Python decorator如何理解 Python 装饰器的调用顺序
【发布时间】:2014-03-24 16:12:54
【问题描述】:

我对以下代码段的调用顺序感到困惑。

#/usr/bin/python


def decorator_no_args(fn):
    if not callable(fn):
        raise TypeError

    def wrapper():
        return fn()

    print "decorator_no_args"
    return wrapper


@decorator_no_args
def foo_no_args():
    print "foo_no_args"


def decorator_args(* args, **kargs):
    def wrapper0(fn):
        def wrapper1(*args, **kargs):
            return fn(*args, **kargs)
        return wrapper1

    print "decorator_args"
    return wrapper0


@decorator_args(1)
def foo_args(arg0):
    print "foo_args"


if __name__ == "__main__":
    foo_no_args()

输出是:

decorator_no_args
decorator_args
foo_no_args

如上所示,函数decorator_args() 未被调用。但是为什么要记录呢?

【问题讨论】:

    标签: python decorator python-decorators


    【解决方案1】:

    两件事:装饰器在函数定义执行时应用@expression 语法采用表达式;装饰时进行评估。

    @decorator_args(1) 行调用decorator_args() 函数,将1 作为参数传入。该调用的 result 被用作装饰器。

    装饰器实际上只是语法糖,这是:

    @decorator_args(1)
    def foo_args(arg0):
        print "foo_args"
    

    实际上是这样执行的:

    def foo_args(arg0):
        print "foo_args"
    foo_args = decorator_args(1)(foo_args)
    

    注意decorator_args(1) 调用。并且它的返回值被再次调用,以产生一个修饰的结果。

    当您查看decorator_args() 时,您会看到它返回了一个装饰器:

    def decorator_args(* args, **kargs):
        def wrapper0(fn):
            def wrapper1(*args, **kargs):
                return fn(*args, **kargs)
            return wrapper1
    
        print "decorator_args"
        return wrapper0
    

    wrapper0 是真正的装饰器;它在调用decorator_args() 时返回。 foo_args() 被传递给wrapper0()(作为fn 参数),原来的函数被wrapper1 替换。

    永远不会调用foo_args 并不重要;每次调用函数时都不会应用装饰器,它们只会应用一次。如果您多次调用foo_no_args()decorator_no_args 消息将不会重复。

    【讨论】:

      【解决方案2】:

      如果我记得,装饰器本质上是接受一个函数作为参数并返回另一个函数(可能相同)的函数。这很有趣。

      输出的前两行(decorator_* 的)来自函数 foo_no_argsfoo_args定义,而不是调用。 p>

      为了更好地理解,看看这个sn-p:

      def my_decorator(func):
          def wrap():
              print "Function ran"
              return func()
          print "Function defined"
          return wrap
      
      @my_decorator
      def my_function():
          print "my_function"
      
      my_function()
      my_function()
      my_function()
      

      输出:

      Function defined
      function ran
      my_function
      function ran
      my_function
      function ran
      my_function
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-28
        • 2015-11-17
        • 2015-02-05
        • 2023-02-08
        • 2017-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多