Fork me on GitHub

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

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

实例一:

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函数的输出与函数的执行的一个先后顺序。

 

 

 

posted @ 2018-06-04 20:27  道阻切长  阅读(1141)  评论(0编辑  收藏  举报