1.如何解决在函数执行之前和执行之后添加功能,调用函数的方式改变的问题。
不改变原有函数的调用方法:函数里面嵌套函数,并且返回嵌套函数login =desc(login)
def desc(fun): ##fun=login def add_info(): print("hello") fun() ##login() print("hi") return add_info def login(): ##print("hello") print("login") ##print("hi") login=desc(login) ##返回值是一个函数 login()
2.装饰器定义:
装饰器的实现是函数里面嵌套函数
装饰器的本质是一个函数,他可以让其他函数在不需要任何代码改动的前提下增加额外的功能
装饰器需要传递一个函数,返回值也是一个函数对象
3.装饰器的应用场景(计时器)
装饰器需求:获取每个函数的执行时间
函数执行之前计算时间
函数执行之后计算时间
【1】字符串拼接效率:“hello”+“world”
“ ”.join(['hello',"world"])
import random import string import time li=[random.choice(string.ascii_letters) for i in range(100)] def timeit(fun): def wrapper(): start_time=time.time() fun() end_time=time.time() print("运行时间:%.6f" %(end_time-start_time)) return wrapper @timeit def con_add(): s=' ' for i in li: s +=(i+",") print(s) @timeit def join_add(): print(",".join(li)) con_add() join_add()
【2】检测列表生成式和map的效率的高低,n为函数传入参数:
[n*2 for i in range(10)]
map(lamdba x: x*2,range(n))
import random import string import time def timeit(fun): def wrapper(*args,**kwargs): start_time=time.time() fun(*args,**kwargs) end_time=time.time() print("运行时间:%.6f" %(end_time-start_time)) return wrapper @timeit def fun_list(n): print([2*n for i in range(n)]) @timeit def fun_map(n): print(list(map(lambda x: x*2,range(n)))) fun_list(100) fun_map(100)
4.装饰器函数属性变化解决方案
装饰的函数有返回值解决方法
如何保留被装饰函数的函数名和帮助文档信息
import random import string import time import functools from functools import reduce li=[random.choice(string.ascii_letters) for i in range(100)] def timeit(fun): @functools.wraps(fun) def wrapper(*args,**kwargs): start_time=time.time() res = fun(*args,**kwargs) end_time=time.time() print("运行时间:%.6f" %(end_time-start_time)) return res return wrapper @timeit def fun_list(n): print([2*n for i in range(n)]) @timeit def fun_map(n): print(list(map(lambda x: x*2,range(n)))) fun_list(10) fun_map(10) print(fun_list.__name__) print(fun_list.__doc__)
例:创建装饰器,要求:创建add_log装饰器,被装饰的函数打印日志信息;日志格式为[字符串时间]
函数名:xxx,运行时间:xxxx,运行返回值结果:xxxx
import functools import time import string def add_log(fun): @functools.wraps(fun) def wrapper(*args,**kwargs): run_time=time.ctime() fun_name=fun.__name__ start_time=time.time() res=fun(*args,**kwargs) end_time=time.time() print("[%s]函数名:%s.运行时间:%.5f,运行返回值结果:%d" %(run_time,fun_name,end_time-start_time,res) ) return res return wrapper @add_log def add(x,y): time.sleep(0.1) return x+y print(add(1,2))
5.装饰器 方法2:
【1】例:需求:用户登录验证的装饰器is_login
如果用户登陆成功,执行被装饰的函数
如果用户登陆不成功,则执行登陆函数
import functools login_users=['admin','root'] def is_login(fun): @functools.wraps(fun) def wrapper(*args,**kwargs): if kwargs.get("name") in login_users: res=fun(*args,**kwargs) return res else: res=login() return res return wrapper @is_login def writeBlog(name): return "编写博客" def login(): return "登陆" def news(): print("新闻") print(writeBlog(name="root"))
【2】判断变量的数据类型
确保函数接受的每个参数都是整数
如果参数不是整数,打印TypeError:参数必须是整形
import functools def required_ints(fun): @functools.wraps(fun) def wrapper(*args,**kwargs): for i in args: if not isinstance(1,int): print("Error:函数参数必须是整形") break else: res=fun(*args,**kwargs) return res return wrapper @required_ints def add(a,b): return a+b @required_ints def myMax(a,b,c,d): return (a,b,c,d) print(add(1,2))
6.带有多个装饰器的函数
def makebold(fun): print("bold1") def wrapper1(*args,**kwargs): print("bold2") return fun(*args,**kwargs) return wrapper1 def makei(fun): print("i1") def wrapper(*args,**kwargs): print("i2") return fun(*args,**kwargs) return wrapper @makebold @makei def login(): return "登陆" print(login())
注意:当有多个装饰其实,从下到上调用装饰器;
真实wrapper内容执行是从上到下执行
7.带有参数的装饰器
例1:创建装饰器,要求:创建add_log装饰器,被装饰的函数打印日志信息;日志格式为[字符串时间]
函数名:xxx,运行时间:xxxx,运行返回值结果:xxxx
import functools import time import string def log(kind): def add_log(fun): @functools.wraps(fun) def wrapper(*args,**kwargs): start_time=time.time() res=fun(*args,**kwargs) end_time=time.time() print("<%s> [%s]函数名:%s.运行时间:%.5f,运行返回值结果:%d" %(kind,time.ctime(),fun.__name__,end_time-start_time,res) ) return res return wrapper return add_log @log("debug") def add(x,y): time.sleep(0.1) return x+y print(add(1,2))
例2:编写装饰器required_types,条件如下:
当装饰器为@required_types(int,float)确保函数接受到的参数都是int类型或者float类型
当装饰器为@required_types(list)确保函数接受到的参数都是list类型
当装饰器为@required_types(str,int)确保函数接受到的参数都是int类型或者str类型
如果不满足条件,打印参数必须为xxxx类型
import functools def required_types(*kinds): def required(fun): @functools.wraps(fun) def wrapper(*args,**kwargs): for i in args: if not isinstance(i,kinds): print("Error:函数参数必须是整形",kinds) break else: res=fun(*args,**kwargs) return res return wrapper return required @required_types(int,float) def add(a,b): return a+b @required_types(int) def myMax(a,b,c,d): return (a,b,c,d) print(add(1,2.0))