python 装饰器
装饰器
装饰器作用:装饰器可以在不改变函数体和函数调用的情况下在该函数执行之前,或者执行之后进行额外的操作
装饰器功能:1.自动执行装饰器函数并将其下面的函数名当作参数传递
2.将装饰器函数的返回值,赋值给被装饰器函数
被装饰器无返回值
def outer(func): def inner(): print('before') func() print('after') return inner @outer def f1(): print('F1'.center(10,'-')) f1()
执行结果:
before ----F1---- after
解析:
1.自动执行outer函数,并将下面的函数名f1当作参数传递
2.将outer函数的返回值,重新赋值给f1,outer的返回值就是inner()函数体,而func() == 老f1(),
此时,新的f1()就是
print('before')
print('F1'.center(10,'-'))
print('after')
被装饰器有返回值
def outer(func): def inner(): print('before') res = func()return res return inner @outer def f1(): return 'F1....' a = f1() print(a)
执行结果:
before
F1....
解析:
当函数有返回值时,同样inner()方法就相当于f1(),也就是说inner()函数的返回值就是老f1()的返回值。inner()函数的返回值就是res,也就是老f1()的返回值。
被装饰器有参数
dict_a = {'aa':123} str_a = 'abc' list_a = [1,2] def outer(func): def inner(*args,**kwargs): print('before') res = func(*args,**kwargs) return res return inner @outer def f1(*args,**kwargs): print(*args,**kwargs) return 'F1....' a = f1(str_a,list_a,dict_a) print(a)
执行结果:
before abc [1, 2] {'aa': 123} F1....
解析:
当被装饰的函数有参数时,装饰器函数的内层函数就相当于被装饰的函数。f1()函数就相当于inner()函数,因为f1()在调用时有参数,所以需要在inner()函数增加参数,大多数情况可以写成inner(*args,**kwargs)万能参数的形式。
双层装饰器
目前有一个小小的需求,写一个小程序,要求用户登录后可以查看home目录,管理员可以查看所有目录,不登录不可以查看
代码如下:
USER_INFO ={} def check_login(func): #验证登录装饰器 def inner(*args,**kwargs): if USER_INFO.get('islogin',None): ret = func(*args,**kwargs) return ret else: print('请登录') return inner def check_admin(func): #验证admin装饰器 def inner(*args,**kwargs): if USER_INFO.get('islogin',None): if USER_INFO.get('usertype',None) ==2: ret =func(*args,**kwargs) return ret else: print('无权查看') else: print('请登录') return inner def login(): user = input('please input your name:') if user == 'admin': USER_INFO['islogin']=True USER_INFO['usertype']=2 else: USER_INFO['islogin']=True USER_INFO['usertype']=1 @check_login def home(): print('home') @check_admin def index(): print('index') def main(): while True: inp = input('1.login 2.home 3.index \n>>>') if inp == '1': login() elif inp =='2': home() elif inp == '3' : index() main()
执行结果:
1.login 2.home 3.index
>>>2
请登录
1.login 2.home 3.index
>>>3
请登录
1.login 2.home 3.index
>>>1
please input your name:xx #xx登录
1.login 2.home 3.index
>>>2 #xx查看home目录
home
1.login 2.home 3.index
>>>3
无权查看
1.login 2.home 3.index
>>>1
please input your name:admin #admin登录
1.login 2.home 3.index
>>>2 #admin查看home目录
home
1.login 2.home 3.index
>>>3 #admin查看index目录
index
1.login 2.home 3.index
>>>
分析:这样做虽然功能可以实现,但是如果要是还有超级管理员或者其他更高权限的用户,还需写更多的装饰器,比较麻烦,代码重用性太高
所以需要用多层装饰器做权限验证
代码如下:
USER_INFO ={} def check_login(func): def inner(*args,**kwargs): if USER_INFO.get('islogin',None): #1 ret = func(*args,**kwargs) #2 return ret #7 else: print('请登录') return inner def check_admin(func): def inner(*args,**kwargs): if USER_INFO.get('usertype',None) ==2: #3 ret =func(*args,**kwargs) #4 return ret #6 else: print('无权查看') return inner def login(): user = input('please input your name:') if user == 'admin': USER_INFO['islogin']=True USER_INFO['usertype']=2 else: USER_INFO['islogin']=True USER_INFO['usertype']=1 @check_login def home(): print('home') @check_login @check_admin def index(): #5 print('index') def main(): while True: inp = input('1.login 2.home 3.index \n>>>') if inp == '1': login() elif inp =='2': home() elif inp == '3' : index() main()
分析这段代码:
def check_login(func): def inner(*args,**kwargs): if USER_INFO.get('islogin',None): #1 ret = func(*args,**kwargs) #2 return ret #7 else: print('请登录') return inner def check_admin(func): def inner(*args,**kwargs): if USER_INFO.get('usertype',None) ==2: #3 ret =func(*args,**kwargs) #4 return ret #6 else: print('无权查看') return inner @check_login @check_admin def index(): #5 print('index')
首先,解释器会先把check_login和check_admin这两个函数加载到内存
然后先解释@check_admin/def index(): 会把它们俩作为一个整体去解释,并定义为new_index函数,其实就是check_admin里的inner函数,index函数就是check_admin里的func函数
此时,解释器会继续解释@check_login/new_index 会把它们作为一个整体去解释,并定义为new_new_index函数,其实就是check_login里的inner函数,new_index函数就是check_login里的func函数
此时,最外层函数就是new_new_index函数,也就是check_login里的inner函数
解释器从下往上解释完后,会从上往下执行函数,先从check_login里的inner函数执行
1.先执行 if USER_INFO.get('islogin',None): #1 ---》条件不满足直接print('请登录')
2. ret = func(*args,**kwargs) #2
3. USER_INFO.get('usertype',None) ==2: #3 ---》条件不满足直接print('无权查看')
4. ret =func(*args,**kwargs) #4
5. def index(): #5
6. return ret #6
7. return ret #7
图文分析:
更牛的装饰器
#!/usr/bin/env python #coding:utf-8 def Before(request,kargs): print 'before' def After(request,kargs): print 'after' def Filter(before_func,after_func): def outer(main_func): def wrapper(request,kargs): before_result = before_func(request,kargs) if(before_result != None): return before_result; main_result = main_func(request,kargs) if(main_result != None): return main_result; after_result = after_func(request,kargs) if(after_result != None): return after_result; return wrapper return outer @Filter(Before, After) def Index(request,kargs): print 'index'