装饰器基础
装饰器的目的是为了给被装饰 对象,增加新功能,或者说增加某种能力
在程序中工具就是函数
如此一来,装饰器指的就是一个函数,被装饰着也是一个函数
总结;装饰器就是用一个函数去拓展另外一个已存在的函数的功能
拓展性是对于一个应用程序来说非常重要的能力,任何应用程序都需要拓展,于是出现了开闭原则
开闭原则:
对修改关闭,对拓展开放
不允许修改源代码以及调用方式
装饰器就是一种可以保证不修改源代码,也不修改调用方式,还能给函数添加新功能的方式
需求: 目前已有一个函数,其功能是从服务器下载一个文件,需求要为这个函数统计下载耗时
import time(下载功能)
def download(filepath):
print('开始下载%s’% filepath)
time.sleep(3)
print('下载完成%s’% filepath)
return '123'
def upload():
print('开始上传’)
time.sleep(3)
print('上传完成’)
return '123'
def outer(func)
def run_time(*args ,**kwargs )
boot_time=time.time()
res=func(*args,**kwargs)
print('耗时',time.time()-boot_time)
return res
return run_time
download = outer(download)
movie = download('大电影’)
print(movie)
upload=outer(upload)
upload()
无参函数:
import time
def download():
print("download run!")
# ===============================
def outer(func):
def run_time(*args,**kwargs): #是为了让装饰函数能接受任何形式任何长度的参数
boot_time = time.time()
res = func(*args,**kwargs) # 将参数在原模原样交给被装饰者
print("耗时:", time.time() - boot_time)
return res # 把原始函数的执行结果 在交给调用者
return run_time
download = outer(download)
# ==============================
# 使用者
download()
有参函数
from functools import wraps
import time
def outer(location):
def logger(func):
@wraps(func) # wrapper.__doc__ = func.__doc__
def wrapper(*args, **kwargs):
"""这是装饰器函数"""
if location == "cmd":
print("时间:%s func:%s" % (time.time(), func.__name__))
elif location == "file":
with open("a.log", "a", encoding="utf-8") as f:
f.write("时间:%s func:%s" % (time.time(), func.__name__))
else:
print("位置错误........必须是 file 或 cmd")
return func(*args, **kwargs)
return wrapper
return logger
@outer("file") # ????? logger = outer("file) test = logger(test)
def test():
"""这是一个test函数"""
print("test run!")
# test()
print(test.__doc__)(功能是调出注释)
装饰器语法糖
"""
语法糖
就是一种简便写法,使你的语法更简洁
"""
# 提供输出日记(日志 什么时候干了什么事)功能
import time
def logger(func):
def wrapper(*args,**kwargs):
print("时间:%s func:%s" % (time.time(),func.__name__))
res = func(*args,**kwargs)
return res
return wrapper
# 该语法就可以帮我们完成对原始函数的伪装,
# 注意 1.必须写在被装饰函数的正上方
# 注意 2.在开发时装饰器必须写在被装饰函数之上
@logger # login = logger(login)
def login():
print("登录成功...")
login()
装饰器在购物车中的使用
is_login = False
# 判断是否登录过的装饰器
def auth(func):
def wrapper(*args,**kwargs):
if is_login:
func(*args,**kwargs)
else:
print("还没有登录过请先登录...")
login()
return wrapper
def login():
global is_login
name = input("name:").strip()
pwd = input("pwd:").strip()
if name == "blex" and pwd == "123":
print("登录成功!")
is_login = True
@auth
def shopping():
print("查看购物车....")
@auth
def collection():
print("查看收藏....")
def main():
while True:
funcs = {"1":login,"2":shopping,"3":collection}
print("""
1.登录
2.购物车
3.收藏夹
""")
res = input(">>>:").strip()
if res in funcs:
funcs[res]()
else:
print("输入有误!")
main()
同时叠加多个装饰器
import time
# 装饰器1
def logger(func):
def wrapper(*args,**kwargs):
print("时间:%s func:%s" % (time.time(),func.__name__))
res = func(*args,**kwargs)
return res
return wrapper
#装饰器2
def timer(func):
def run_time(*args,**kwargs):
boot_time = time.time()
res = func(*args,**kwargs) # 这是在执行原始的download函数也就是被装饰的函数
print("耗时:", time.time() - boot_time)
return res # 把原始函数的执行结果 在交给调用者
return run_time
# 该语法就可以帮我们完成对原始函数的伪装,
# 注意 1.必须写在被装饰函数的正上方
# 注意 2.在开发时装饰器必须写在被装饰函数之上
@timer # logger = timer(logger)
@logger # login = logger(login)
def login():
print("登录成功...")
login()
# 在嵌套多个装饰器时,执行的顺序是 从上往下依次调用,结束的顺序反过来,是从下往上
# 实际开发中 没什么用.....
小节
1.装饰器
什么是装饰器,一种为其他函数增加新功能的函数就是装饰器
装饰器是基于闭包函数实现的
可以在遵循开闭原则的前提下,扩展新功能
无参:
def outer(func):
def wrapper(*args,**kwargs):
# 新功能
res = func(*args,**kwargs)
return res
return wrapper
有参
def big_outer(arg):
def outer(func):
def wrapper(*args,**kwargs):
# 新功能
res = func(*args,**kwargs)
return res
return wrapper
return outer