我们通过两个实例来解开我们的疑惑:
实例一:
复制代码
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函数的输出与函数的执行的一个先后顺序。
来源:抚顺市博远电子,如涉及版权问题请与我们联系。
TAG
软件定制,软件开发,瀚森HANSEN,辽宁,沈阳,抚顺