python 装饰器执行顺序迷思
当解释器执行下面这段代码时,实际上按照从下到上的顺序已经依次调用了decorator_a和decorator_b,这是会输出对应的Get in decorator_a和Get in decorator_b。 这时候f已经相当于decorator_b里的inner_b。但因为f并没有被调用,所以inner_b并没有调用,依次类推inner_b内部的inner_a也没有调用,所以Get in inner_a和Get in inner_b也不会被输出。@decorator_b @decorator_a def f(x): print 'Get in f' return x * 2然后最后一行当我们对传入参数1进行调用时,inner_b被调用了,它会先打印Get in inner_b,然后在inner_b内部调用了inner_aGet in inner_a, 然后再inner_af, 并且将结果作为最终的返回。这时候你该知道为什么输出结果会是那样,以及对装饰器执行顺序实际发生了什么有一定了解了吧。 test git:(master) python Python 2.7.11 (default, Jan 22 2016, 08:29:18) [GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import test13 Get in decorator_a Get in decorator_b >>> test13.f(1) Get in inner_b Get in inner_a Get in f 2 >>> test13.f(2) Get in inner_b Get in inner_a Get in f 4 >>>在实际应用的场景中,当我们采用上面的方式写了两个装饰方法比如先验证有没有登录@login_required, 再验证权限够不够时@permision_allowed时,我们采用下面的顺序来装饰函数:
昨天来源:cnblogs
装饰器是Python用于封装函数或代码的工具,网上可以搜到很多文章可以学习,我在这里要讨论的是多个装饰器执行顺序的一个迷思。
疑问大部分涉及多个装饰器装饰的函数调用顺序时都会说明它们是自上而下的,比如下面这个例子:
def decorator_a(func): print 'Get in decorator_a' def inner_a(*args, **kwargs): print 'Get in inner_a' return func(*args, **kwargs) return inner_a def decorator_b(func): print 'Get in decorator_b' def inner_b(*args, **kwargs): print 'Get in inner_b' return func(*args, **kwargs) return inner_b @decorator_b @decorator_a def f(x): print 'Get in f' return x * 2 f(1)上面代码先定义里两个函数:decotator_a, decotator_b, 这两个函数实现的功能是,接收一个函数作为参数然后返回创建的另一个函数,在这个创建的函数里调用接收的函数(文字比代码绕人)。最后定义的函数f作为装饰函数。在当我们以1为参数调用装饰后的函数的顺序是什么呢(这里为了表示函数执行的先后顺序,采用打印输出的方式来查看函数的执行顺序)?如果不假思索根据自下而上的原则来判断地话,先执行decorator_a再执行decorator_b, 那么会先输出Get in decotator_a,再输出Get in decotator_bGet in inner_b。然而事实并非如此。实际上运行的结果如下:
Get in decorator_a Get in decorator_b Get in inner_b Get in inner_a Get in f函数和函数调用的区别为什么是先执行inner_b再执行inner_a呢?为了彻底看清上面的问题,得先分清两个概念:函数和函数调用。上面的例子中f称之为函数,f(1)称之为函数调用,后者是对前者传入参数进行求值的结果。在Python中函数也是一个对象,所以f是指代一个函数对象,它的值是函数本身,f(1)是对函数的调用,它的值是调用的结果,这里的定义下f(1)的值2。同样地,拿上面的decorator_a函数来说,它返回的是个函数对象inner_a,这个函数对象是它内部定义的。在inner_a里调用了函数func,将func的调用结果作为值返回。装饰器函数在被装饰函数定义好后立即执行其次得理清的一个问题是,当装饰器装饰一个函数时,究竟发生了什么。现在简化我们的例子,假设是下面这样的:
def decorator_a(func): print 'Get in decorator_a' def inner_a(*args, **kwargs): print 'Get in inner_a' return func(*args, **kwargs) return inner_a @decorator_a def f(x): print 'Get in f' return x * 2正如很多介绍装饰器的文章里所说:
@decorator_a def f(x): print 'Get in f' return x * 2 # 相当于 def f(x): print 'Get in f' return x * 2 f = decorator_a(f)所以,当解释器执行这段代码时,decorator_a已经调用了,它以函数f作为参数, 返回它内部生成的一个函数,所以此后f指代的是decorater_a里面返回的inner_a。所以当以后调用f时,实际上相当于调用inner_af的参数会传给inner_a, 在调用inner_a时会把接收到的参数传给inner_a里的funcff一样。疑问的解释当理清上面两方面概念时,就可以清楚地看清最原始的例子中发生了什么。当解释器执行下面这段代码时,实际上按照从下到上的顺序已经依次调用了decorator_a和decorator_b,这是会输出对应的Get in decorator_a和Get in decorator_b。 这时候f已经相当于decorator_b里的inner_b。但因为f并没有被调用,所以inner_b并没有调用,依次类推inner_b内部的inner_a也没有调用,所以Get in inner_a和Get in inner_b也不会被输出。@decorator_b @decorator_a def f(x): print 'Get in f' return x * 2然后最后一行当我们对传入参数1进行调用时,inner_b被调用了,它会先打印Get in inner_b,然后在inner_b内部调用了inner_aGet in inner_a, 然后再inner_af, 并且将结果作为最终的返回。这时候你该知道为什么输出结果会是那样,以及对装饰器执行顺序实际发生了什么有一定了解了吧。 test git:(master) python Python 2.7.11 (default, Jan 22 2016, 08:29:18) [GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import test13 Get in decorator_a Get in decorator_b >>> test13.f(1) Get in inner_b Get in inner_a Get in f 2 >>> test13.f(2) Get in inner_b Get in inner_a Get in f 4 >>>在实际应用的场景中,当我们采用上面的方式写了两个装饰方法比如先验证有没有登录@login_required, 再验证权限够不够时@permision_allowed时,我们采用下面的顺序来装饰函数: