1,装饰器的初识
装饰器:装饰,装修,房子本来就可以住,如果装修不影响住,而且体验更佳 器:工具 开放封闭原则: ''' 开放:对代码的拓展是开放的, 封闭:对源码的修改是封闭的。 ''' 装饰器:完全遵循开放封闭原则。 ''' 在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。 ''' # 装饰器就是一个函数
装饰器的演变过程
例子:
给一段代码A添加一个功能,这个功能可以计算出代码A运行了多少时间。
版本一:
# 版本一:
import time
def index():
'''有很多代码''' # 模拟网络延迟
time.sleep(3) # 模拟网络延迟单位是3秒
print('欢迎登录博客园首页!')
def dirty():
'''有很多代码''' # 模拟网络延迟
time.sleep(3) # 模拟网络延迟单位是3秒
print('欢迎登录日记页面!')
start_time = time.time()
index()
end_time = time.time()
print(end_time - start_time)
start_time = time.time()
dirty()
end_time = time.time()
print(end_time - start_time)
就是只能在代码前后添加功能,复用性不强
版本二:
# 版本二
import time
def index():
'''有很多代码''' # 模拟网络延迟
time.sleep(1) # 模拟网络延迟单位是1秒
print('欢迎登录博客园首页!')
def dirty():
'''有很多代码''' # 模拟网络延迟
time.sleep(2) # 模拟网络延迟单位是2秒
print('欢迎登录日记页面!')
def timmer(f): # 可以传参
start_time = time.time()
f()
end_time = time.time()
print(end_time - start_time)
timmer(index) # 传进去哪个函数名就检测哪个函数
原来index()函数源码没有变化,给原函数添加了一个新的功能测试原函数的执行效率的功能 满足开放封闭原则吗?原函数的调用方式改变了
版本三:
不改变原函数的调用方式。
# 版本三
import time
def index():
'''有很多代码''' # 模拟网络延迟
time.sleep(1) # 模拟网络延迟单位是1秒
print('欢迎登录博客园首页!')
def timmer(f): # 可以传参
def inner():
start_time = time.time()
f()
end_time = time.time()
print(f'函数的执行效率是{end_time - start_time}')
return inner
index = timmer(index) # index()
index()
如果有五百个函数则每此调用之前都要重新赋值 类似:index = timmer(index)
版本四:语法糖优化
# 版本四
def timmer(f): # 可以传参
start_time = time.time()
f()
end_time = time.time()
print(f'函数的执行效率是{end_time - start_time}')
@timmer # @timmer的意思就等同于index = timmer(index)
def index():
'''有很多代码''' # 模拟网络延迟
time.sleep(1) # 模拟网络延迟单位是1秒
print('欢迎登录博客园首页!')
ret = index
版本四也有缺点:不能返回函数的返回值
版本五:
# 版本五
import time
# timmer()装饰器
def timmer(f): # 可以传参
def inner():
start_time = time.time()
r = f()
end_time = time.time()
print(f'函数的执行效率是{end_time - start_time}')
return r
return inner
@timmer # @timmer的意思就等同于index = timmer(index)
def index():
'''有很多代码''' # 模拟网络延迟
time.sleep(1) # 模拟网络延迟单位是1秒
print('欢迎登录博客园首页!')
return 666
加上装饰器不应该改变原函数的返回值,所以666应该返回给下面的ret 但是下面的这个ret实际接收的是inner函数的返回值,而666返回给的是装饰器里面的 f()也就是r,我们现在要解决的问题就是将r给inner的返回值。
版本六:被装饰函数带参数
# 版本六
import time
# timmer()装饰器
def timmer(f): # 可以传参
def inner(n):
start_time = time.time()
r = f(n)
end_time = time.time()
print(f'函数的执行效率是{end_time - start_time}')
return r
return inner
@timmer # @timmer的意思就等同于index = timmer(index)
def index(name):
'''有很多代码''' # 模拟网络延迟
time.sleep(1) # 模拟网络延迟单位是1秒
print(f'欢迎{name}登录博客园首页!')
return 666
index('小红') # 相当于inner('小红') 因此inner()也要有参数,f()也要有参数
print(index('小红'))
版本七:多个参数的传递
# 版本七:多个参数的装饰器传参
import time
# timmer()装饰器
def timmer(f): # 可以传参
def inner(*args, **kwargs):
start_time = time.time()
r = f(*args, **kwargs)
end_time = time.time()
print(f'函数的执行效率是{end_time - start_time}')
return r
return inner
@timmer # @timmer的意思就等同于index = timmer(index)
def index(name):
'''有很多代码''' # 模拟网络延迟
time.sleep(0.5) # 模拟网络延迟单位是1秒
print(f'欢迎{name}登录博客园首页!')
return 666
@timmer
def dirty(name, age):
'''有很多代码''' # 模拟网络延迟
time.sleep(0.5) # 模拟网络延迟单位是2秒
print(f'欢迎{age}岁的{name}登录日记页面!')
@timmer
def student(name, age, high, count):
print(f'{name}今年{age}岁,身高{high}学的有{count}专业。')
index('小红')
print(index('小红'))
dirty('alex', '18')
student('alex', '19', '185', ['音乐', '数学', '语文', '英语'])
装饰器模版
# 标准版的装饰器(模版)
def wapper(f):
def inner(*args, **kwargs):
'''
添加新功能的代码区,被装饰函数执行前的操作
'''
ret = f(*args, **kwargs) # 调用添加功能的源代码
'''
添加新功能的代码区,被装饰函数执行后的操作
'''
return ret
return inner
标准装饰器的使用示例
**同级目录下擦护功能键一个passwd.txt的文件,内容如下
大壮|123 太白|666 b哥|999 alex|123
def login(f):
def inner(*args, **kwargs):
dic = {}
with open('passwd.txt', encoding='utf-8') as file:
for line in file:
data = line.split("\n")
a, b = data[0].split("|")
dic[a] = b
count = 0
flag = True
while flag:
username = str(input('用户名:'))
password = str(input('密 码:'))
if username in dic.keys() and password == dic[username]:
print('登录成功!')
ret = f(username)
return ret
else:
print(f'用户名或密码不正确,剩下{2 - count}次机会')
count += 1
if count == 3:
flag = False
return inner
@login
def login_2(name):
time.sleep(2)
print(f'欢迎{name}登录博客园')
login_2()
2,带参数的装饰器
参数装饰器模版
# 模版
def ff(xxx):
def func(f):
def inner(*args, **kwargs):
ret = f(*args, **kwargs)
return ret
return inner
return func
需求:
将登录的日志信息写到auth.log文件中
所有的购物信息写到operate.log文件中
import time
def logger(path):
def log(func):
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
with open(path, encoding='utf-8', mode='a') as f:
msg = f"在{time.strftime('%Y-%m-%d %H:%M:%S')}执行了{func.__name__}\n\t"
f.write(msg)
return ret
return inner
return log
@logger('login.log') # 装饰器参数,可以直接将日志写到auth.log文件中,也不需要修改装饰器,装饰器外层再嵌套一个函数
def login():
print('登录的逻辑')
@logger('register.log') # # 装饰器参数,可以直接将日志写到register.log文件中,也不需要修改装饰器
def register():
print('注册的逻辑')
@logger('show_goods.log') # 装饰器参数,可以直接将日志写到show_goods.log文件中,也不需要修改装饰器
def show_goods():
print('查看所有商品信息')
@logger('add_goods.log') # 装饰器参数,可以直接将日志写到add_goods.log文件中,也不需要修改装饰器
def add_goods():
print('商品加入购物车')
login()
register()
3,装饰器的应用
装饰器的应用:登录认证
装饰器的应用场景很多,这里用登录认证来演示一下
模拟博客园的登录。装饰器的认证功能
装饰器的需求:
访问被装饰函数之前,写一个三次登录认证功能, 登录成功后:让其访问被装饰器的函数,登录没有成功,不能访问。
def login():
print('请完成登录')
def register():
print('请完成注册')
# 装饰器
'''
你的装饰器完成:访问被装饰函数之前,写一个三次登录认证功能,
登录成功后:让其访问被装饰器的函数,登录没有成功,不能访问。
'''
login_status_dic = {'username': None,
'status': False}
def auth(f):
def inner(*args, **kwargs):
'''访问函数之前的操作,3次认证登录,不成功不执行下一步'''
if login_status_dic['status']:
ret = f(*args, **kwargs)
'''访问函数之后的操作'''
return ret
else:
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
if username == 'taibai' and password == '123':
print('登录成功')
login_status_dic['username'] = username
login_status_dic['status'] = True
ret = f(*args, **kwargs)
return ret
else:
print('登录失败')
return inner
@auth
def article():
print('欢迎访问文章页面')
@auth
def comment():
print('欢迎访问评论页面')
@auth
def dairy():
print('欢迎访问日记页面')
article()
comment()
dairy()
4,函数的总结
# 仅限关键字参数
def func(a, b, *args, c):
print(a, b)
print(c)
print(args)
func(1, 2, 3, 4, 8, 5, 6, c=666)
# *
a, b, *c = (1, 2, 3, 4, 5, 6, 7, 8)
print(a, b, c)
a, *b, c = [11, 22, 33, 44, 55, 66]
print(a, b, c)
a, *b, c = range(10)
print(a, b, c)
# 全局名称空间:global
def func():
global name
name = 'alex'
func()
print(name)
name = '太白'
def func():
global name
name = 'alex'
print(name)
func()
print(name)
nonlocal
def func():
name = '太白'
def inner():
nonlocal name
name = 'alex'
print(name)
inner()
print(name)
func()
# 函数名
def func():
pass
print(func) # <function func at 0x000002A6F7136798>
# 获取自由变量
def wrapper(a):
name = '太白'
def inner():
print(a)
print(name)
return inner
ret = wrapper('烧饼')
print(ret())
print(ret.__code__.co_freevars)
# 装饰器
def func(f):
def inner(*args, **kwargs):
ret = f(*args, **kwargs)
return ret
return inner
更多内容可以查看自己学python的过程,简单笔记。-CSDN博客
更多内容可以查看自己学python的过程,简单笔记。-CSDN博客
更多内容可以查看自己学python的过程,简单笔记。-CSDN博客