执行outer函数,将index做为参数传递,python
将outer函数的返回值,从新赋值给index编程
装饰器能够在函数执行前和执行后执行其余的附加功能,这种在代码运行期间动态增长功能的方式,称之为“装饰器”(Decorator),装饰器的功能很是强大,可是理解起来有些困难,所以我尽可能用最简单的例子一步步的说明这个原理。app
写代码要遵循开发封闭原则,虽然在这个原则是用的面向对象开发,可是也适用于函数式编程,简单来讲,它规定已经实现的功能代码不容许被修改,但能够被扩展,即:函数式编程
假设我定义了一个函数f,想要在不改变原来函数定义的状况下,在函数运行前打印出start,函数运行后打印出end,要实现这样一个功能该怎么实现?看下面如何用一个简单的装饰器来实现:函数
# 使用@语法放在函数的定义上面 至关于执行 f=outer(f),此时f赋值成为了一个新的outer函数, # 此时f函数就指向了outer函数的返回值inner,inner是一个函数名,定义在oute函数里面 # 原来的f是函数名可简单理解为一个变量,做为outer函数的参数传递进去了 此时参数func至关于f def outer(func): # 定义一个outer函数做为装饰器 def inner(): # 若是执行inner()函数的话步骤以下: print('start') # 一、首先打印了字符‘start’, r=func() # 二、执行func函数,func函数至关于def f(): print('中') print('end') # 三、接着函数打印‘end’ return r # 四、将func函数的结果返回 return inner @outer def f(): # f=outer(f)=innner print('中') f() # f()至关于inner(),执行inner函数的步骤看上面定义处的注释<BR>#打印结果顺序为 start 中 end
在实际中,咱们的装饰器可能应用到不一样的函数中去,这些函数的参数都不同,那么咱们怎么实现一个对任意参数都能实现功能的装饰器?还记得我写函数那篇博客中,就写一种能够接受任意参数的函数,下面来看看如何将其应用到装饰器中去。spa
#其实只要将上面一种不带参数的装饰器修改一下就能够了 #修改也很简单,只需将inner和func的参数改成 (*args,**kwargs) #其余实现的过程和上面一种同样,就再也不介绍了 def outer(func): def inner(*args,**kwargs): print('start') r=func(*args,**kwargs) # 这里func(*args,**kwargs)至关于f(a,b) print('end') return r return inner @outer def index(a,b): print(a+b) m=index(1,4) # f(1,4)至关于inner(1,4) 这里打印的结果为 start 5 end
print m
一、outer函数加载
二、遇到outer装饰器
三、执行outer函数,将index函数(被装饰的函数)做为参数传递func=index()
四、加载inner函数,
五、将outer函数的返回值inner(这是一个函数),从新赋值给index(也就是说此时的index指向inner函数)
六、执行inner函数
七、打印‘start’
八、执行res = func(a1, a2)(也就是执行被装饰器装饰的函数(index函数))
九、将index函数的返回值赋值给res
十、打印‘end’
十一、将inner函数的返回值 res 赋值给index函数
十二、打印m
当一个装饰器不够用的话,咱们就能够用两个装饰器,固然理解起来也就更复杂了,当使用两个装饰器的话,首先将函数与内层装饰器结合而后在与外层装饰器相结合,要理解使用@语法的时候到底执行了什么,是理解装饰器的关键。这里仍是用最简单的例子来进行说明。3d
def outer2(func2): def inner2(*args,**kwargs): print('开始') r=func2(*args,**kwargs) print('结束') return r return inner2 def outer1(func1): def inner1(*args,**kwargs): print('start') r=func1(*args,**kwargs) print('end') return r return inner1 @outer2 # 这里至关于执行了 f=outer1(f) f=outer2(f),步骤以下 @outer1 #一、f=outer1(f) f被从新赋值为outer1(1)的返回值inner1, def f(): # 此时func1为 f():print('f 函数') print('f 函数') #二、f=outer2(f) 相似f=outer2(inner1) f被从新赋值为outer2的返回值inner2 # 此时func2 为inner1函数 inner1里面func1函数为原来的 f():print('f 函数') f() # 至关于执行 outer2(inner1)() >>开始 # 在outer函数里面执行,首先打印 ‘开始 ’ >>start # 执行func2 即执行inner1函数 打印 ‘start’ >>f 函数 # 在inner1函数里面执行 func1 即f()函数,打印 ‘f 函数’ >>end # f函数执行完,接着执行inner1函数里面的 print('end') >>结束 # 最后执行inner2函数里面的 print('结束')
前面的装饰器自己没有带参数,若是要写一个带参数的装饰器怎么办,那么咱们就须要写一个三层的装饰器,并且前面写的装饰器都不太规范,下面来写一个比较规范带参数的装饰器,下面来看一下代码,你们能够将下面的代码自我运行一下orm
import functools def log(k=''): #这里参数定义的是一个默认参数,若是没有传入参数,默认为空,能够换成其余类型的参数 def decorator(func): @functools.wraps(func) #这一句的功能是使被装饰器装饰的函数的函数名不被改变, def wrapper(*args, **kwargs): print('start') print('{}:{}'.format(k, func.__name__)) #这里使用了装饰器的参数k r = func(*args, **kwargs) print('end') return r return wrapper return decorator @log() # fun1=log()(fun1) 装饰器没有使用参数 def fun1(a): print(a + 10) fun1(10) # print(fun1.__name__) # 上面装饰器若是没有@functools.wraps(func)一句的话,这里打印出的函数名为wrapper @log('excute') # fun2=log('excute')(fun2) 装饰器使用给定参数 def fun2(a): print(a + 20) fun2(10)
一个函数能够被多个装饰器装饰吗? 好比两个装饰器 对象
会先将 函数交个最下层@装饰器将处理结果在交给其上一层@装饰器 即先交给w2 再交给w1blog
def w1(func): def inner(*args,**kwargs): # 验证1 # 验证2 # 验证3 return func(*args,**kwargs) return inner def w2(func): def inner(*args,**kwargs): # 验证1 # 验证2 # 验证3 return func(*args,**kwargs) return inner @w1 @w2 def f1(arg1,arg2,arg3): print 'f1'
双层装饰器原理