• 关于多个装饰器装饰一个函数执行顺序的问题


    我们通过两个实例来解开我们的疑惑:

    实例一:

    def war1(func):
        def inner(*args, **kwargs):
            print("======war1 start=====")
            func(*args, **kwargs)
            print("======war1 end=====")
        return inner
    def war2(func):
        def inner(*args,**kwargs):
            print("======war2 start=====")
            func(*args,**kwargs)
            print("======war2 end=====")
        return inner
    @war1
    @war2
    def f():
        print("****self****")
    f()

    实际输出结果为:

    ======war1 start=====
    ======war2 start=====
    ****self****
    ======war2 end=====
    ======war1 end=====

    好吧这个结果似乎有点出乎我们的意料:不是说好的谁近谁先来的嘛(我裤子都脱了,结果。。。)

    我们自己臆想的结果:

    ======war2 start=====
    ======war2 end=====
    ======war1 start=====
    ======war1 end=====
    ****self****

    那么首先我们知道我们为一个函数装饰其实就相当于:

    f = war1(f)或者
    f = war2(f)                ####这个时候f=inner,而不再是原来的函数。只是用户不知道而已。

    那么问题来了:

    当走到这一步的时候说明,两个inner函数已经执行了。

    也就是他们发生在我们真正的调用之前,那么真正调用的时候才是我们按照我们的就近原则,也就是限制性war2中的代码,在执行war1中的代码。

     实例二:

    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)

    实际执行结果为:

    执行结果
    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_a ,传给 f 的参数会传给 inner_a , 在调用 inner_a 时会把接收到的参数传给 inner_a 里的 func 即 f ,最后返回的是 f 调用的值,所以在最外面看起来就像直接再调用 f 一样。


    那么对于实例一与实例二,还有一点不同的,哈哈哈,那就是被装饰函数的执行顺序,在两个实例中是不一样的,这是为什么呢?

    这个就跟我们的装饰器没什么关系了:
    主要是因为inner函数的输出与函数的执行的一个先后顺序。

     
  • 相关阅读:
    直播源列表
    MySQL为什么"错误"选择代价更大的索引
    C#中ConfigureAwait的理解(作者Stephen)
    理解C#中的 async await
    C#中Task.Delay() 和 Thread.Sleep() 区别
    扁平结构数据变成嵌套结构数据(树状结构)
    判断两个数组相同 两个对象相同 js
    嵌套结构数据(树状结构)变成扁平结构不带子元素(children)
    嵌套结构数据(树状结构)变成扁平结构带有子元素(children)
    2022.1.11学习日志
  • 原文地址:https://www.cnblogs.com/zhangsanfeng/p/9135280.html
Copyright © 2020-2023  润新知