1、定义:假设我们要增强一个函数的功能,比如,在函数调用前后自动打印日志,但又不希望改变这个函数的源代码,这种在代码运行期间动态增加功能且又不改变源代码的方式,成为装饰器(Decorator)。本质上,decorator就是一个返回函数的高阶函数
2、示例:

如上图中的原函数为index(),我们通过装饰器为其增加了一个计算运行时间的功能,但是没有改变源代码,这就是为其增加了一个装饰器,装饰器的功能就是计时。
关键点:@的语法,@timmer等同于进行了如下操作:index=timmer(index),函数名+()就是调用函数,一定要记住!!好多地方想不通原因就是在这里!
思想就是把部内函数func()换成被装饰函数index()然后再运行闭包函数就好了(可能说的有点简单)
3、复杂一点的例子,代参数的,并且是用于多个参数不确定的函数的装饰器
import time
def timmer(func):
def wrapper (*args,**kwargs):##注意注意*args和**kwargs
start_time=time.time()
func(*args,**kwargs)##注意注意*args和**kwargs
stop_time=time.time()
print("run time is %s"%(stop_time-start_time))
return wrapper
@timmer##注意注意位于被装饰函数最上方,且单独占一行
def home(name):
time.sleep(2)
print("welcome to %s home page"%name)
@timmer
def auth(name,password):
print(name,password)
@timmer
def tell():
print('=======')
home('dragon')
auth('egon','123')
tell()
4、装饰用户认证功能
#现在是对index()函数增加了用户认证功能,源代码没有变
def auth2(auth_type): def auth(func): def wrapper(*args,**kwargs): if auth_type == 'file': name=input('username:') password=input('password:') if name=='zhejiangf4'and password == 'sbasb': print('auth successful') res=func(*args,**kwargs) return res else: print('auth error') elif auth_type =="sql": print("还他妈不会玩") return wrapper return auth @auth2(auth_type="file") #==>@auth==>index=auth(index),所以auth2作用就是传了一个值 def index(): print('Welcome to index page!') index()
5、再给上面的函数加一个时间模块
import time
def timmer(func):
def wrapper():
start_time=time.time()
func()
stop_time=time.time()
print(stop_time-start_time)
return wrapper
def auth2(auth_type):
def auth(func):
def wrapper(*args,**kwargs):
if auth_type == 'file':
name=input('username:')
password=input('password:')
if name=='zhejiangf4'and password == 'sbasb':
print('auth successful')
res=func(*args,**kwargs)
return res
else:
print('auth error')
elif auth_type =="sql":
print("还他妈不会玩")
return wrapper
return auth
@timmer
@auth2(auth_type="file")#
def index():
print('Welcome to index page!')
index()
上面函数的运行原理需要细说一下
#先把大体的概念说一下:
# def aaa():#装饰函数
# @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)))
#上边的例子是下边这个规律
#founc=bbb(aaa('a')(func))
#index=timmer(auth2(auth_type="list")(func))
#index=timmer(auth(func))
#index=timmer(wrapper_dixia)
#index=wrapper_shangbian
#index()=wrapper_shangbian()
#index()=wrapper_dixia()
6、eval函数:会把字符串里面的东西读出来执行,结果必须要赋值,不然砸电脑
m=input(">>:")
m=eval(m)
print(m,type(m))
>>:{"name":"agon"}
{'name': 'agon'} <class 'dict'>
>>:["agon"]
['agon'] <class 'list'>
>>:print(123)
7、给认证装饰器增加一个登陆后再次调用是免认证的功能(字典,只在内存中能行)
import time
current_login={'name':None,'login':False}#建立一个字典,字典存储登录状态
def timmer(func):
def wrapper():
start_time=time.time()
func()
stop_time=time.time()
print('run time is %s'%(stop_time-start_time))
return wrapper
def auth2(auth_type='file'):
def auth(func):
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 == 'zhejiangF4' and password == 'sb945':
print('auth successful')
res = func(*args,**kwargs)
current_login['name']=name#存储登录状态
current_login['login']=True
return res
else:
print('auth error')
elif auth_type == "sql":
print("haibuhui")
return wrapper
return auth
@timmer
@auth2(auth_type="file")
def index():
print('welcome to index page')
@auth2("file")
def home():
print("welcome to home page")
index()
home()#第一次执行index()函数是需要登录认证,但第二次执行home时就不需要再认证了
8、怎样在增加装饰器后还可以打印原函数的注释内容
import time
from functools import wraps#从函数工具中调用wraps模块
def timmer(func):
@wraps(func)#它就可以让你打印出的index.__doc__编程原函数的"dashabi"而不是wrapper函数的"000"
def wrapper(*args,**kwargs):
'000'
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s'%(stop_time-start_time))
return res
return wrapper
@timmer
def index():
"dashabi"
print("from index")
index()
print(index.__doc__)