装饰器总结
-
开放封闭原则
- 对拓展是开放的,允许代码拓展,添加新功能
- 对修改是封闭的,不能修改函数的源码和调用方式
-
装饰器
- 在不改变原被装饰函数的源代码以及调用方式的前提下,为其添加额外的功能
# 版本一,测试每个函数都要写一遍代码. import time def func1(): time.sleep(2) # 暂停2秒 print('测试延迟') time1 = time.time() # 返回的格林尼治时间,是此时此刻距离1970年1月1日0时0分0秒的时间秒数.也叫时间戳 func1() time2 = time.time() print(time2 - time1)
# 版本二,只能测试特定的函数 import time def func1(): time.sleep(2) print('测试延迟') def ceshi(): time1 = time.time() func1() time2 = time.time() print(time2 - time1) ceshi()
# 版本三,虽然没有改变原函数代码,但是改变了执行方式,不符合开放封闭原则 import time def func1(): time.sleep(2) print('测试延迟') def ceshi(func): time1 = time.time() func() time2 = time.time() print(time2 - time1) ceshi(func1)
# 版本四,实现真正的开放封闭原则:装饰器 import time def func1(): time.sleep(2) print('测试延迟') def timer(func): def ceshi(): time1 = time.time() func() time2 = time.time() print(time2 - time1) return ceshi func1 = timer(func1) func1()
# 带返回值的装饰器 import time def func1(): time.sleep(2) print('测试延迟') return '测试成功' def timer(func): def ceshi(): time1 = time.time() ret = func() time2 = time.time() print(time2 - time1) return ret return ceshi func1 = timer(func1) print(func1())
# 被装饰函数带参数的装饰器 import time def func1(name): time.sleep(2) print(f'{name}测试延迟') return f'{name}测试成功' def timer(func): def ceshi(name): time1 = time.time() ret = func(name) time2 = time.time() print(time2 - time1) return ret return ceshi func1 = timer(func1) print(func1('太上老君'))
# 被装饰函数不定参数的装饰器 import time def func1(*args, **kwargs): time.sleep(2) print(f'{args}测试延迟') print(f'{kwargs}测试延迟') return f'{args, kwargs}测试成功' def timer(func): def ceshi(*args, **kwargs): time1 = time.time() ret = func(*args, **kwargs) time2 = time.time() print(time2 - time1) return ret return ceshi func1 = timer(func1) print(func1('太上老君', '元始天尊', 我叫='通天教主'))
# 标准的装饰器:语法糖 import time def timer(func): def ceshi(*args, **kwargs): time1 = time.time() ret = func(*args, **kwargs) time2 = time.time() print(time2 - time1) return ret return ceshi @timer # 相当于 func1 = timer(func1),没有特殊意义,为了简单化 def func1(*args, **kwargs): time.sleep(2) print(f'{args, kwargs}测试延迟') return f'{args, kwargs}测试成功' print(func1('太上老君', '元始天尊', 我叫='通天教主'))
# 带参数的装饰器 # 准备好qq文件用于保存qq密码,tiktok用于保存抖音密码 def get_dic(file_name): # 获取密码库 dic = {} with open(file_name, mode='r', encoding='utf-8') as f1: for line in f1: username, psw = line.strip().split('|') dic[username] = psw return dic def login(dic): # 3次登陆功能 time = 3 while time > 0: username = input('请输入用户名:').strip() psw = input('请输入密码:').strip() if dic.get(username) == psw: return True time -= 1 return False def wrapper_out(file_name): # 装饰器本体 def wrapper(func): def inner(): dic = get_dic(file_name) # 获取相应的密码库 if login(dic): # 调用登陆函数 ret = func() return ret return False return inner return wrapper @wrapper_out('qq') def qq(): print('欢迎登陆QQ~~~~') return '登陆成功' print(qq()) @wrapper_out('tiktok') def tiktok(): print('欢迎访问抖音~~~') return '登陆成功' print(tiktok())
# 多个装饰器装饰同一个函数的运行顺序 def w1(func): # func == 原函数text def inner(): print('正在运行w1.inner....1') # 2 func() # 原函数text() print('正在运行w1.inner....2') # 4 return inner def w2(func): # func == w1.inner def inner(): print('正在运行w2.inner....1') # 1 func() # w1.inner() print('正在运行w2.inner....2') # 5 return inner @w2 # text = w2(text) 后面的text是w1.inner, 前面的text == w2.inner @w1 # text = w1(text) 后面的text是原函数, 前面的text == w1.inner def text(): print('正在运行被装饰的函数...') # 3 text() # w2.inner()