装饰器的概念
- 装饰器就是用来装饰函数,是函数里面嵌套函数;
- 装饰器的本质是一个函数, 它可以让其他函数在不需要做任何代码改动的前提下增加额外的功能;
- 装饰器需要传递一个函数, 返回值也是一个函数对象.
如何使用装饰器
装饰要求:
执行程序之前==“欢迎光临”,
执行程序之后==”欢迎再次光临”.问题: 在函数执行之前和执行之后添加功能, 调用函数的方式改变了.
不改变原有函数的调用方法: 函数里面嵌套函数,并且返回嵌套的函数login=desc(login)
def desc(fun): # fun = login # 1). 需要传递一个函数, 要装饰的函数
def add_info(): # 2). 装饰器函数里面嵌套函数
print("欢迎光临")
fun() # login()
print("欢迎再次光临")
return add_info # 3). 返回值是嵌套的函数对象
调用装饰器的两种方式: @descpython里的语法糖; logout = desc(logout)
@desc
def login():
# print("欢迎光临")
print("login......")
# print("欢迎再次光临")
login()
def logout():
print("logout......")
logout = desc(logout) # 返回值是一个函数
logout()
装饰器的应用场景
计时器的装饰器
装饰器需求: 获取每个函数的执行时间
1).函数执行之前计算时间;
2).函数执行之后计算时间
实验1:看字符串拼接的效率==>join效率较高
1). “hello” + “world”
2). ” “.join([‘hello’, “world”])实验2:检测列表生成式和map的效率高低, n为函数传入的参数==>旗鼓相当的对手
1). [n*2 for i in range(n)]
2). map(lambda x:x*2, range(n))
import random
import string
import time
li = [ random.choice(string.ascii_letters) for i in range(100)]
def timeit(fun): # fun_list
def wrapper(*args, **kwargs): # 接收可变参数和关键字参数
# args: 元组 kwargs: 字典 args=(5,)
# 函数执行之前
start_time = time.time()
# 执行函数
fun(*args, **kwargs) # args解包, 5,| 对于元组解包, 对于字典解包
# 执行函数之后
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))
@timeit # fun_list=timeit(fun_list) # fun_list = wrapper
def fun_list(n):
print([2*i for i in range(n)])
@timeit
def fun_map(n):
print(list(map(lambda x:x*2, range(n))))
con_add()
join_add()
fun_list(500)
fun_map(500)
记录日志的装饰器
创建装饰器, 要求如下:
1). 创建add_log装饰器, 被装饰的函数打印日志信息;
2). 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx
import functools
import time
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, 运行时间:%.5f, 运行返回值结果:%d"
%(time.ctime(), 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))
用户登录的装饰器
需求: 用户登陆验证的装饰器is_login
1). 如果用户登陆成功, 则执行被装饰的函数;
2). 如果用户登陆不成功, 则执行登陆函数
import functools
login_users = ['admin', 'root']
def is_login(fun): # fun: writeBlog
@functools.wraps(fun)
def wrapper(*args, **kwargs): # name="admin" # kwargs={"name":"admin"}
# 判断写博客的这个用户是否登陆成功;
if kwargs.get("name") in login_users:
res = fun(*args, **kwargs)
return res
else:
res=login()
return res
return wrapper
# 必须登陆成功后才执行
@is_login # writeBlog = is_login(writeBlog)
def writeBlog(name):
return "写博客"
def login():
return "...登陆..."
# 是否登陆成功都可以执行代码
def news():
print("...新闻...")
print(writeBlog(name="admin"))
print(writeBlog(name="admin123"))
函数带参数的装饰器
装饰器required_types, 条件如下:
1).当装饰器为@required_types(int,float)确保函数接收到的每一个参数都是int或者float类型;
2). 当装饰器为@required_types(list)确保函数接收到的每一个参数都是list类型;
3).当装饰器为@required_types(str,int)确保函数接收到的每一个参数都是str或者int类型;
4). 如果参数不满足条件, 打印 TypeError:参数必须为xxxx类型
import functools
def required_types(*kinds): # kinds
def required(fun):
@functools.wraps(fun)
def wrapper(*args, **kwargs): # args=(1,2)
for i in args: # i=1
if not isinstance(i , kinds):
print("函数所有参数并非", 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 max(a, b, c, d)
print(add(1,2.0))
print(myMax(1,3,2,5))
print(myMax(1,7.2,2,5))
多个装饰器
def makebold(fun):
print("bold1")
def wrapper1(*args, **kwargs):
print("bold2")
return fun(*args, **kwargs) # wrapper
return wrapper1
def makei(fun): # fun=login
print("i1")
def wrapper(*args, **kwargs):
print("i2")
return fun(*args, **kwargs)
return wrapper
# 当有多个装饰器时, 从下到上调用装饰器,
# 真实wrapper内容执行是从上到下执行.
@makebold # login = makebold(login) # login为wrapper1
@makei # login = makei(login) # login为wrapper
def login():
return "登陆"
print(login())