装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作。
def f1(arg):
arg()
def func():
print ('123')
f1(func) ======>f1接收的参数是一个函数
注:func返回的是内存地址,func()才是执行func这个函数
=====================================================
=====================================================
=====================================================
def f1():
print 'f1' ========>连接数据库
def f2():
print 'f2' ========>连接redis
def f3():
print 'f3' ========>去硬盘拿数据
。。。。。。。
我这三个函数已经都写好了,并且已经都封闭了(即不能再往函数里面去做修改了),这个时候老板有个任务,希望对每个函数做验证,而函数又已经都是写好了的,已经封闭了,该怎么办?
思路是这样的,还是上面的例子(语法是错误的,只是解释原理):
def f1(arg):
print (‘验证’)
arg()
def func():
print ('123')
#1.将被调用函数封装到另外一个函数里边
func = f1(func)
#2.将原函数重新赋值
func()
我们看见这样就解决了问题(只是原理,语法并不是这样)。
=========================================================
=========================================================
=========================================================
具体做法是这样的:
def auth(func): =======>我在上边新加了一个具有验证功能的函数,下面执行这个函数,就会发现将f1作为参数传给func函数,以后 就等价于func = f1 ======>func() <======>f1()
def inner(): ==========>函数里又嵌套一个函数
print ('before')
func() =========f1 =====>原函数
return inner
def f1():
print 'f1' ========>连接数据库
ret1 = auth(f1) = def inner():
print ('before')
f1()#原来f1
f1 = ret1
def f2():
print 'f2' ========>连接redis
ret2 = auth(f2) = def inner():
print ('before')
f2()#原来f2
f2 = ret2
def f3():
print 'f3' ========>去硬盘拿数据
ret3 = auth(f3) = def inner():
print ('before')
f3()#原来f3
f3 = ret3
。。。。。。。
result = auth(f1) = def inner():
print ('before')
func()
result() #它现在就等于执行inner()这个函数了,执行inner这个函数就是执行了f1这个原函数了
上面的写法是为了理解装饰器的原理和工作过程,不过自己都看不懂了,
=================================================================================================
=================================================================================================
=================================================================================================
完整写好的是这样的:
def auth(func):
def inner():
print ('before,验证') ====>在执行函数之前增加一个验证功能。
func()
print ('after,写日志') ====>在执行函数之后增加一个写日志功能。
return inner
@auth
def f1():
print 'f1' ========>连接数据库
@auth
def f2():
print 'f2' ========>连接redis
@auth
def f3():
print 'f3' ========>去硬盘拿数据
。。。。。。。
总结:
第一步:先写一个嵌套函数,将需要增加的功能写在内层函数里
第二步:在每个需要新增功能的函数上面加上装饰器即@auth
====================================================================================================
====================================================================================================
====================================================================================================
装饰器去装饰含参数的函数:
def auth(func): ====>装饰没有参数的函数
def inner():
print ('before,验证') ====>在执行函数之前增加一个验证功能。
func()
print ('after,写日志') ====>在执行函数之前增加一个写日志功能。
return inner
def auth_arg(func): ====>重新定义一个装饰器装饰有参数的函数
def inner(arg):
print ('before,验证') ====>在执行函数之前增加一个验证功能。
func(arg)
print ('after,写日志') ====>在执行函数之前增加一个写日志功能。
return inner
@auth
def f1():
print 'f1' ========>连接mysql
@auth_arg
def f4(arg): ========>连接oracle(带参数)
print 'f4,arg'
缺点:总结以上的方案我们发现,我没带参数写个装饰器,我带1个需要写个装饰器,带2个需要写个装饰器。。。。。。。
完美解决方案就是利用万能动态参数,如下,这样不管你传不传参数,不管你传几个参数就都没有问题了。
------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------
def auth(func):
def inner(*args,**kwargs):
print ('before,验证')
func(*args,**kwargs)
print ('after,写日志')
return inner
@auth
def f1():
print 'f1' ========>连接mysql
@auth
def f4(arg): ========>连接oracle(带1个参数)
print 'f4,arg'
@auth
def f5(arg1,arg2,arg3,arg4): ========>连接redis(带4个参数)
print 'f5,arg1,arg2,arg3,arg4'
==================================================================================================
==================================================================================================
==================================================================================================
装饰器去装饰含返回值的函数:
def auth(func):
def inner(*args,**kwargs):
print ('before,验证')
temp = func(*args,**kwargs)
print ('after,写日志')
return temp
return inner
@auth
def fetch_host_list(arg): =====>获取主机列表
host_list = ['h1','h2','h3']
return host_list
=====================================================================================================
=====================================================================================================
=====================================================================================================
装饰器实现登录验证原理(这个是装饰器应用最多的场景):
def login():
name = 'rooney'
if name == 'rooney':
return True
else:
return False
def auth(func):
def inner(*args,**kwargs):
is_login = login()
if not is_login:
return "你输入的用户名不正确"
temp = func(*args,**kwargs)
print ('after,写日志')
return temp
return inner
@auth
def fetch_host_list(arg): =====>获取主机列表
host_list = ['h1','h2','h3']
return host_list
=======================================================================================================
=======================================================================================================
=======================================================================================================
装饰器实现token验证:
def login(key):
local = 'fdsareqwrwq12345d2srwq'
if local == key:
return True
else:
return False
def auth(func):
def inner(*args,**kwargs):
#fetch_server_list('test',token=key) ====>业务线传了两个参数进来
key = kwargs.pop('token')
is_login = login(key)
if not is_login:
return "你输入的用户名不正确"
temp = func(*args,**kwargs)
print ('after,写日志')
return temp
return inner
@auth
def fetch_host_list(arg): =====>获取主机列表
host_list = ['h1','h2','h3']
return host_list
==========================================================================================================
==========================================================================================================
==========================================================================================================
装饰器之多装饰器(盒子模型):
def w1(func):
def inner(*args,**kwargs):
print ('w1,before')
func(*args,**kwargs)
print ('w1,after')
return inner
def w2(func):
def inner(*args,**kwargs):
print ('w2,before')
func(*args,**kwargs)
print ('w2,after')
return inner
@w2
@w1
def foo():
print ('foo')
foo()
返回结果竟然是这样:
w2,before
w1,before
foo
w1,after
w2,after
套盒子,foo是一个盒子,上面加个w1装饰器就相当于外面又套了一层盒子,再加一个装饰器就相当于再套了个盒子,那么你打开的时候就是从外往里打开拿出来。
=====================================================================================
=====================================================================================
=====================================================================================
装饰器之装饰器加参数:
#!/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'
比如说:下面两个装饰器,一个带参数,一个不带参数
@w1
1.执行w1函数
2.将w1函数的返回值赋值给被装饰器装饰的函数的函数名
@w2
1.执行w2函数,得到返回值,ret
2.创建装饰器,@ + ret结合;@ret
3.。。。。。。。
1.执行ret函数
2.将ret函数的返回值赋值给被装饰器装饰的函数的函数名