一、叠加装饰器
在同一个被装饰对象中,添加多个装饰器,并执行,模板:
1 模板: 2 @装饰器1 3 @装饰器2 4 ... 5 def 被装饰对象(): 6 pass
注意:装饰器在调用被装饰对象时才会执行添加的功能
- 叠加装饰器:
- 装饰的顺序: 由下到上装饰
- 执行的顺序: 由上往下
注意: 无论inner中出现任何判断,最后都要返回“调用后的被装饰对象” func(*args, **kwargs)
# 需求: 为被装饰对象,添加统计时间 与 登录认证功能
import time
# 定义一个全局变量,表示用户是否验证通过
login_info = {
'login': False
}
# 登录功能
def login():
# 判断用户没有登录时,执行登录功能
name = input("username:").strip()
pwd = input('password:').strip()
if name == 'abc' and pwd == '123':
print('登录成功!')
login_info['login'] = True
else:
print('登录失败!')
# 登录认证装饰器
def login_auth(func):
def inner1(*args, **kwargs):
"""
注意: 无论inner中出现任何判断,
最后都要返回“调用后的被装饰对象” func(*args, **kwargs)
"""
if login_info.get('login'):
res = func(*args, **kwargs)
return res
else:
login()
return func(*args, **kwargs)
return inner1
# 统计时间装饰器
def time_record(func):
def inner2(*args, **kwargs):
print('开始统计')
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return res
return inner2
# 下载电影功能
"""
- 叠加装饰器:
- 装饰的顺序: 由下到上装饰
- 执行的顺序: 由上往下
"""
@time_record # inner2 = time_record(inner1地址)
@login_auth # inner1 = login_auth(func)
# @time_record
def func():
print('start')
time.sleep(2)
print('end')
func()
# login() # 执行的顺序: 先执行time_ record功能,再执行login_auth功能 # 统计登录时间 + 下载时间 # func() # 装饰顺序 # @login_auth # inner1 = login_auth(inner2) # @time_record # inner = time_record(download_movie) # 执行顺序: # 先执行login_auth, 再执行time_record # 只统计下载电影的时间 # login() # 先调用登录,模拟用户已登录
二、有参装饰器
# 无参装饰器: 装饰在被装饰对象时,没有传参数的装饰器。 ''' # 以下是无参装饰器 @wrapper1 # inner1 = wrapper1(inner2) @wrapper2 # inner2 = wrapper2(inner3) @wrapper3 '''
了解无参装饰器后,我们可以再实现一个用来为被装饰器对象添加认证功能的装饰器,需要传入用户级别参数
# 有参装饰器: 在某些时候,我们需要给用户的权限进行分类 ''' # 以下是有参装饰器 @wrapper1(参数1) # inner1 = wrapper1(inner2) @wrapper2(参数2) # inner2 = wrapper2(inner3) @wrapper3(参数3) '''
# 需求,给登录功能再添加一个可以验证用户级别的功能,传入级别参数
def user_auth(user_level): # 'VIP'
def wrapper(func):
def inner(*args, **kwargs):
if user_level == 'VIP':
print('VIP用户')
res = func(*args, **kwargs)
return res
else:
print('普通用户')
return func(*args, **kwargs)
return inner
return wrapper
# 被装饰对象
# wrapper = user_auth('普通')
# @wrapper
# @user_auth('VIP') # wrapper = user_auth('普通用户')
# @wrapper #<--- 返回结果(wrapper) <---- user_auth()
# 有参装饰器的使用
@user_auth('VIP')
def func():
pass
func()
有参装饰器,最外一层函数参数可以随意添加,所以装饰器对象最多包含三层
三、wraps
wraps是一个修复工具,修复的是被装饰对象的空间,使用方法
from functools import wraps
def wrapper(func):
@wraps(func) # 修改名称空间:inner ---> func
def inner(*args, **kwargs):
"""
此处是装饰器的注释
:param args:
:param kwargs:
:return:
"""
res = func(*args, **kwargs)
return res
return inner
@wrapper
def func():
"""
此处是func函数的注释
:return:
"""
pass
# 函数对象.__doc__:查看函数内部的注释
print(func.__doc__)
# 结果就是返回func里面的注释
四、迭代器
迭代的工具
迭代:
迭代指的是重复迭代,每一次迭代都是基于上一次的结果而来的
迭代器:
迭代器指的是迭代取值的工具,它可以迭代取值
可迭代对象:
凡是内部有str.__iter__()方法的都是可迭代对象。
可迭代对象有:字符串str、列表list、元组tuple、字典dict、集合set、文件f
获取迭代器:
通过可迭代对象.__iter__(), 得到的返回值就是 “迭代器对象”。
迭代器是迭代取值的工具,作用是迭代取值
如何迭代取值:
迭代对象.__next__() 每执行一次,都会从迭代器对象中取出一个值
str1 = '123456' iter_str = str1.__iter__() print(iter_str) # iterator指的是迭代器对象 print(iter_str.__next__()) print(iter_str.__next__()) print(iter_str.__next__()) print(iter_str.__next__()) print(iter_str.__next__()) print(iter_str.__next__()) # 因为迭代器中的值已经取完 # print(iter_str.__next__()) # 报错StopIteration
- 总结: 可迭代对象 VS 迭代器对象:
- 获取可迭代对象: 定义序列类型(str, list, set, tuple, dict, f)
- 特点:
内置有__iter__()
- 获取迭代器对象: 通过可迭代对象调用.__iter__()得到返回值
- 特点:
内置有__next__()
- 迭代器对象的优点:
- 优点:
1.不依赖于索引迭代取值。
2.节省内存空间。
- 缺点:
1.取指定某个值麻烦
2.每次取值都要从第一个值开始,无法同过索引取值。
当迭代器中的值取完时,继续执行会报错,这里补充一个try语法防止此问题
list1 = [1,2,3,4]
iter_list = list1.__iter__()
while True:
try:
print(iter_list.__next__()) # 若不捕获异常,当取完迭代器对象后会报错
# 当遇到StopIteration异常,会立即执行此处代码
except StopIteration:
break
for循环原理
语法: for i in 可迭代对象:
in: 可迭代对象 ----> 内部会自动调用.__iter__() ---> 迭代器对象
for line in list1:
# 迭代器对象.__next__()
# 不依赖于索引取值
list1 = [1,2,3,4]
for i in list1: # list1是可迭代对象 ----> 内部会自动调用.__iter__() ---> 迭代器对象
# 迭代器对象.__next__()
print(i)
# 依赖于索引取值
list1 = [1,2,3,4]
n = 0
while n < len(list1):
print(list1[n])
n += 1
迭代器本质上是一个可迭代对象
文件本质上既是迭代器对象,也是可迭代对象。
# 唯独文件比较特殊: 因为文件从读取出来的时候就是一个迭代器对象
# f ---> 可迭代对象, 还是迭代器对象
# 文件既是可迭代对象,也是迭代器对象。
f = open('test.txt','r',encoding='utf-8')
iter_f = f.__iter__()
print(iter_f is f) # True
可迭代对象不一定是迭代器对象
set1 = {1,2,3,4}
iter_set1 = set1.__iter__()
iter_set1.__next__()
# 迭代器对象也是一个可迭代对象
# 判断可迭代对象是否是迭代器对象
print(iter_set1.__iter__() is iter_set1) # True
print(iter_set1 is set1) # False
# 可迭代对象不一定是迭代器对象