python装饰器
1.1装饰器(decorator)
什么是装饰器:
器即函数
1.装饰器可以理解为给一个函数,做修饰,而不修改函数本身。
2.装饰器定义:本质就是函数,decorator功能就是为其他函数添加新的功能。
装饰器的的原则
装饰器=高阶函数+函数嵌套+闭包
装饰器的前提原则:不能修改被装饰函数的源代码,和函数的调用方式
1.1.1高阶函数
高阶函数定义:
1.函数接收的参数是一个函数名。
2.函数的返回值是一个函数。
3.满足上述条件任意一个,都是高阶函数
1.1.2函数嵌套
函数嵌套
python语言中的嵌套:定义一个函数的时候,函数体还能定义另一个函数。
在其他语言(例c语言),在一个函数调用另一个函数,叫嵌套
1.1.3闭包
存储在子封闭作用域(函数)的行为叫做闭包
一个闭包就是一个函数,只不过函数内部带上了一个额外的变量。
闭包关键特点就是它会记住自已被定义时的环境
1.2一步一步理解装饰器
1 def go(): 2 print("python") 3 #该函数功能执行go() ,显示出python 4 go()
现在我们要增强go()这个自定义函数的功能,比如在函数调用前自动打印出python是什么样的语言,但有不想在修改go()函数,这种在代码运行期间动态为其添加功能,就称之为装饰器(decorator)。
1.现在给go()函数加功能
1 #一个装饰器的基本框架 2 def deco(func): 3 def wrapper(): 4 func() #执行你传的go的函数 5 print("一个高级语言") 6 return wrapper 7 def go(): 8 print("python") 9 go = deco(go) #得到结果wrappe的函数r 10 go() # 执行wrapper函数 ——执行函数func() 函数也就是的go()函数 11 #结果 12 python 13 一个高级语言 14 15 #上面就是一个装饰器功能的基本体现,没有修改go函数的源代码,也没有修改go()函数的执行方式,也给go函数加上了一个新功能(高级语言) ,
但是上面每次执行,都需要做一个函数赋值操作,才能执行go() ,这是不完美的
本质上:装饰器(decrator)就是一个返回函数的高阶函数,上面的deco,就是一个装饰器,接收函数做参数,并返回一个函数,需要借助python的@语法,@装饰器
1 def deco(func): 2 def wrapper(): 3 func() 4 print("一个高级语言") 5 return wrapper 6 @deco 7 def go(): 8 print("python") 9 go() 10 #结果 11 python 12 一个高级语言 13 14 #现在才相当于一个合格的装饰器 15 16 把@deco放到go()函数的定义处,相当于执行了go=deco(go)
上面deco()是一个装饰器,返回一个函数,所以原来的go()函数仍然存在,
只是现在同名的go变量指向了新的函数,于是调用go()函数将执行新函数,
即在go()函数中返回的wrapper()函数
2.给被装饰器函数加参数和返回值
1 def deco(func): 2 def wrapper(*args,**kwargs): 3 res = func(*args,**kwargs) #这里就相当于闭包 4 print("一门高级语言") 5 return res 6 return wrapper 7 8 @deco 9 def go(x,y): 10 print("python",x,y) 11 return "done" 12 go(3,5) 13 # 结果 14 python 15 一个高级语言 16 17 # 为什么要给装饰器加参数,如果被装饰的函数里面有参数,我们的装饰器是不是器也要加相应的参数, 18 我们的装饰器为什么要给wrapper(*args,**kwargs) func(*args,**kwargs),可接收任意参数,因为我们被装饰的函数可能都是不同的的参数,而这个装饰器,需要给很多函数做装饰,但是很多函数的参数,功能都是不一样的,因此我们定义装饰器 的函数参数应该是加可变长参数 19 20 #为什么给装饰里面加返回值 21 我们被装饰的函数,一般是有返回值,而执行装饰器(@decorator) 所以需要给wrapper 加上返回值来return fun()的执行结果,来保持被装饰的函数的一致性。
3.给装饰器加参数
如果装饰器本身需要传入参数,那就需要编写一个返回装饰器的高阶函数,也就是在原来装饰器上,做闭包处理,在加上一层函数。
1 def auth_book(auth=None): 2 print(auth) 3 def deco(func): 4 def wrapper(*args,**kwargs): 5 res = func(*args,**kwargs) #这里就相当于闭包 6 print("一门高级语言") 7 return res 8 return wrapper 9 return deco 10 @deco("book") #装饰器加参数 跟go=deco("book")(go)类似 11 def go(x,y): 12 print("python",x,y) 13 go(3,5)
3层嵌套的装饰器的效果是这样的
1 go=auth_book("book")(go)
1 user_list=[ 2 {'name':'yj','passwd':'123'}, 3 {'name':'xixi','passwd':'123'}, 4 {'name':'xiha','passwd':'123'}, 5 {'name':'lala','passwd':'123'}, 6 ] 7 8 current_user={'username':None,'login':False} 9 def auth(auth_type='file'): 10 def auth_deco(func): 11 def wrapper(*args,**kwargs): 12 if auth_type == 'file': 13 if current_user['username'] and current_user['login']: 14 res=func(*args,**kwargs) 15 return res 16 username=input('用户名: ').strip() 17 passwd=input('密码: ').strip() 18 19 for index,user_dic in enumerate(user_list): 20 if username == user_dic['name'] and passwd == user_dic['passwd']: 21 current_user['username']=username 22 current_user['login']=True 23 res=func(*args,**kwargs) 24 return res 25 26 else: 27 print('用户名或者密码错误,重新登录') 28 elif auth_type == 'ldap': 29 print('巴拉巴拉小魔仙') 30 res=func(*args,**kwargs) 31 return res 32 return wrapper 33 return auth_deco 34 35 36 #auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file') 37 #就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数 38 @auth(auth_type='ldap') 39 def index(): 40 print('欢迎来到主页面') 41 42 @auth(auth_type='ldap') 43 def home(): 44 print('这里是你家') 45 @auth(auth_type="file") 46 def shopping_car(): 47 print('查看购物车啊亲') 48 49 def order(): 50 print('查看订单啊亲') 51 52 # print(user_list) 53 index() 54 # print(user_list) 55 home() 56 shopping_car()