函数装饰器
一 什么是装饰器
装饰器补充:http://www.cnblogs.com/luchuangao/p/6842293.html
器即函数
装饰即修饰,意指为其他函数添加新功能
装饰器定义:本质就是函数,功能是为其他函数添加新功能 #装饰器本身就是函数,被装饰的也是函数。
为什么要用装饰器:
及开放封闭原则。
代码上线后,就是为了尽量避免修改,不修改原函数的源代码和调用方式,并添加新的功能。 # 函数及定义和使用。
装饰器语法:
在被装饰上的正上方写一个@,它会把@这一行下面这一行的函数传递到函数里,再重新赋值给index。
func就是index函数,print(func)返回得是index内存地址。
无参装饰器:
(1):
输出: welcome to oldboy run time is 3.000171661376953
执行过程:
# 函数应该先定义后使用。 import time def timmer(func): # 定义函数就相当于定义变量名,就相当于把函数的代码绑定到一个名字上面了。 #1,定义变量名 #3 func值就是index def wrapper(): #4 开始执行timmer里面的代码,只要碰到def就跟定义变量名一样,它里边定义的代码全不用管,只要不执行就不用管它。#7 start_time=time.time() #8 # print(func) func() #9 func就是最原始的index stop_time=time.time() #14 print('run time is %s' %(stop_time-start_time)) #15 return wrapper #5 return wrapper 就是return wrapper的内存地址 # index=timmer(index) @timmer #2 timmer要运行timmer(index),所以要跳回去 #10 def index(): #11 time.sleep(3) #12 print('welcome to oldboy') #13 index() #6 index就是wrapper函数,wrapper是一个闭包函数,里边包含了一个状态,就是func。
(2): # 第一次是home,第二次是home("name")
输出: welcome to dragon home page run time is 2.0001144409179688 egon 123 run time is 0.0 ------------ run time is 0.0
注意:传参数,需要加上*args,**kwargs
(3):
输出: my_max function run time is 0.0 -------- 2
注意:如果原函数需要有返回值,则装饰器也需要设置return res。完整正确的无参装饰器写法就是以上写法。
有参装饰器:
(1): #第一步是函数()的效果,第二步是@auth的效果
输出:还他妈的不会玩
#有参函数执行流程 def auth2(auth_type): #1 #3 def auth(func): #4 #6 def wrapper(*args,**kwargs): #7 #10 if auth_type == 'file': #11 name=input('username: ') password=input('password: ') if name == 'zhejiangF4' and password == 'sb945': print('auth successfull') res=func(*args,**kwargs) return res else: print('auth error') elif auth_type == 'sql': #12 print('还他妈不会玩') #13 return wrapper #8 return auth #5 @auth2(auth_type='sql') #2 def index(): print('welcome to inex page') # @auth # def home(): # print('welcome to home page') index() #9
多个装饰器:
#多个无参装饰器: # @aaa # def func(): # pass # # func=aaa(func) # @ccc # @bbb # @aaa # def func(): # pass # # func=ccc(bbb(aaa(func))) #多个有参装饰器 # @ccc('c') # @bbb('b') # @aaa('a') # def func(): # pass # # func=ccc('c')(bbb('b')(aaa('a')(func)))
多个装饰器应用:
import time current_login={'name':None,'login':False} def timmer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) #my_max(1,2) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper def auth2(auth_type='file'): def auth(func): # print(auth_type) def wrapper(*args,**kwargs): if current_login['name'] and current_login['login']: res=func(*args,**kwargs) return res if auth_type == 'file': name=input('username: ') password=input('password: ') if name == 'luchuan' and password == '123': print('auth successfull') res=func(*args,**kwargs) current_login['name']=name current_login['login']=True return res else: print('auth error') elif auth_type == 'sql': print('还他妈不会玩') return wrapper return auth @timmer @auth2(auth_type='file') #@auth #index=auth(index) def index(): print('welcome to inex page') @auth2() def home(): print('welcome to home page') #调用阶段 index() home()
装饰器帮助信息补充:
import time from functools import wraps def timmer(func): @wraps(func) def wrapper(*args,**kwargs): 'sssssssssssss' # 不加wraps,就会返回'sssssss'帮助信息 start_time=time.time() func(*args,**kwargs) #home(name) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return wrapper @timmer def func(x): 'func test' print(x) func(1) print(func.__doc__) # 查看帮助信息的两种方式 # print(help(func)) #不加wraps,输出sssssssss #加上wraps,则输出:from test
二 装饰器需要遵循的原则
1.不修改被装饰函数的源代码(开放封闭原则)
2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式
三 实现装饰器知识储备
装饰器=高阶函数+函数嵌套+闭包
装饰器:一个外部函数、一个内部函数、一个return 、如果是有参装饰器,外部再包一层函数。
四 高阶函数
高阶函数定义:
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def foo(): print('我的函数名作为参数传给高阶函数') def gao_jie1(func): print('我就是高阶函数1,我接收的参数名是%s' %func) func() def gao_jie2(func): print('我就是高阶函数2,我的返回值是%s' %func) return func gao_jie1(foo) gao_jie2(foo) 高阶函数示范
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#高阶函数应用1:把函数当做参数传给高阶函数 import time def foo(): print('from the foo') def timmer(func): start_time=time.time() func() stop_time=time.time() print('函数%s 运行时间是%s' %(func,stop_time-start_time)) timmer(foo) #总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式 把函数当做参数传给高阶函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名 import time def foo(): print('from the foo') def timmer(func): start_time=time.time() return func stop_time=time.time() print('函数%s 运行时间是%s' %(func,stop_time-start_time)) foo=timmer(foo) foo() #总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能 函数返回值是函数名
高阶函数总结
1.函数接收的参数是一个函数名
作用:在不修改函数源代码的前提下,为函数添加新功能,
不足:会改变函数的调用方式
2.函数的返回值是一个函数名
作用:不修改函数的调用方式
不足:不能添加新功能
五 函数嵌套
def father(name): print('from father %s' %name) def son(): print('from son') def grandson(): print('from grandson') grandson() son() father('林海峰')
六 闭包
''' 闭包:在一个作用域里放入定义变量,相当于打了一个包 ''' def father(name): def son(): # name='alex' print('我爸爸是 [%s]' %name) def grandson(): # name='wupeiqi' print('我爷爷是 [%s]' %name) grandson() son() father('林海峰')
七 无参装饰器
无参装饰器=高级函数+函数嵌套
基本框架
1 #这就是一个实现一个装饰器最基本的架子 2 def timer(func): 3 def wrapper(): 4 func() 5 return wrapper
加上参数
1 def timer(func): 2 def wrapper(*args,**kwargs): 3 func(*args,**kwargs) 4 return wrapper
加上功能
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 func(*args,**kwargs) 6 stop_time=time.time() 7 print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time)) 8 return wrapper
加上返回值
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res=func(*args,**kwargs) 6 stop_time=time.time() 7 print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time)) 8 return res 9 return wrapper
使用装饰器
1 def cal(array): 2 res=0 3 for i in array: 4 res+=i 5 return res 6 7 cal=timer(cal) 8 cal(range(10))
语法糖@
1 @timer #@timer就等同于cal=timer(cal) 2 def cal(array): 3 res=0 4 for i in array: 5 res+=i 6 return res 7 8 cal(range(10))
八 装饰器应用示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, ] current_user={'username':None,'login':False} def auth_deco(func): def wrapper(*args,**kwargs): if current_user['username'] and current_user['login']: res=func(*args,**kwargs) return res username=input('用户名: ').strip() passwd=input('密码: ').strip() for index,user_dic in enumerate(user_list): if username == user_dic['name'] and passwd == user_dic['passwd']: current_user['username']=username current_user['login']=True res=func(*args,**kwargs) return res break else: print('用户名或者密码错误,重新登录') return wrapper @auth_deco def index(): print('欢迎来到主页面') @auth_deco def home(): print('这里是你家') def shopping_car(): print('查看购物车啊亲') def order(): print('查看订单啊亲') print(user_list) # index() print(user_list) home() 无参装饰器
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, ] current_user={'username':None,'login':False} def auth(auth_type='file'): def auth_deco(func): def wrapper(*args,**kwargs): if auth_type == 'file': if current_user['username'] and current_user['login']: res=func(*args,**kwargs) return res username=input('用户名: ').strip() passwd=input('密码: ').strip() for index,user_dic in enumerate(user_list): if username == user_dic['name'] and passwd == user_dic['passwd']: current_user['username']=username current_user['login']=True res=func(*args,**kwargs) return res break else: print('用户名或者密码错误,重新登录') elif auth_type == 'ldap': print('巴拉巴拉小魔仙') res=func(*args,**kwargs) return res return wrapper return auth_deco #auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file') #就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数 @auth(auth_type='ldap') def index(): print('欢迎来到主页面') @auth(auth_type='ldap') def home(): print('这里是你家') def shopping_car(): print('查看购物车啊亲') def order(): print('查看订单啊亲') # print(user_list) index() # print(user_list) home() 带参装饰器
参考链接:http://www.cnblogs.com/linhaifeng/articles/6140395.html
参考链接:http://www.cnblogs.com/yuanchenqi/articles/5828233.html#3503895