装饰器
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__)