叠加装饰器与迭代器
Posted xy-han
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了叠加装饰器与迭代器相关的知识,希望对你有一定的参考价值。
一、叠加装饰器
叠加装饰器的定义
在同一个被装饰对象中,添加多个装饰器并执行
每一个新的功能都应该被放到一个新的装饰器,否则代码冗余,可扩展性差。
叠加装饰器:
装饰的顺序:由下到上装饰
执行的顺序:由上往下
注意:无论inner中出现任何判断最后都要返回“调用后的被装饰对象”。
‘‘‘ 叠加装饰器: 在同一个被装饰对象中,添加多个装饰器,并执行。 @装饰1 @装饰2 @装饰3 def 被装饰对象(): pass 注意: 装饰器在调用被装饰对象时才会执行添加的功能。 - 叠加装饰器: - 装饰的顺序: 由下到上装饰 - 执行的顺序: 由上往下 注意: 无论inner中出现任何判断,最后都要返回“调用后的被装饰对象” func(*args, **kwargs) ‘‘‘ # def wrapper(func): # def inner(*args, **kwargs): # # 注册 # res = func(*args, **kwargs) # # 登录 # return res # # return inner # 需求: 为被装饰对象,添加统计时间 与 登录认证功能 import time user_info = { ‘user‘: None } # 登录功能 def login(): # 判断用户没有登录时,执行 # 登录功能 # global user username = input(‘请输入账号: ‘).strip() password = input(‘请输入密码: ‘).strip() with open(‘user.txt‘, ‘r‘, encoding=‘utf-8‘) as f: for line in f: print(line) name, pwd = line.strip(‘ ‘).split(‘:‘) # [tank, 123] if username == name and password == pwd: print(‘登录成功!‘) user_info[‘user‘] = username return True else: print(‘登录失败!‘) return False # 登录认证装饰器 def login_auth(func): # func---》 download_movie def inner1(*args, **kwargs): ‘‘‘ 注意: 无论inner中出现任何判断, 最后都要返回“调用后的被装饰对象” func(*args, **kwargs) ‘‘‘ # 登录认证 if user_info.get(‘user‘): # res = download_movie(*args, **kwargs) res = func(*args, **kwargs) return res else: flag = login() # 添加用户是否登录判断 if flag: 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(f‘消耗时间为: {end_time - start_time}‘) return res return inner2 # 下载电影功能 ‘‘‘ - 叠加装饰器: - 装饰的顺序: 由下到上装饰 - 执行的顺序: 由上往下 ‘‘‘ @time_record # inner2 = time_record(inner1地址) @login_auth # inner1 = login_auth(download_movie) def download_movie(): print(‘正在下载电影...‘) time.sleep(2) print(‘下载电影完成...‘) return ‘GTWZ.mp4‘ # login() # 执行的顺序: 先执行time_record功能,再执行login_auth功能 # 统计登录时间 + 下载时间 # download_movie() # 装饰顺序 # @login_auth # inner1 = login_auth(inner2) # @time_record # inner2 = time_record(download_movie) # def download_movie(): # print(‘正在下载电影...‘) # time.sleep(2) # print(‘下载电影完成...‘) # return ‘GTWZ.mp4‘ # 执行顺序: # 先执行login_auth, 再执行time_record # 只统计下载电影的时间 # login() # 先调用登录,模拟用户已登录 download_movie()
叠加装饰器模板
def wrapper1(func): def inner1(*args, **kwargs): print(‘1---start‘) # 被裝飾對象在調用時,如果還有其他裝飾器,會先執行其他裝飾器中的inner # inner2 res = func(*args, **kwargs) print(‘1---end‘) return res return inner1 def wrapper2(func): def inner2(*args, **kwargs): print(‘2---start‘) res = func(*args, **kwargs) print(‘2---end‘) return res return inner2 def wrapper3(func): def inner3(*args, **kwargs): print(‘3---start‘) res = func(*args, **kwargs) print(‘3---end‘) return res return inner3 ‘‘‘ 叠加裝飾器的裝飾順序與執行順序: - 裝飾順序: 调用wrapper装饰器拿到返回值inner 由下往上裝飾 - 執行順序: 调用装饰过后的返回值inner 由上往下執行 ‘‘‘ @wrapper1 # index《---inner1 = wrapper1(inner2) @wrapper2 # inner2 = wrapper2(inner3) @wrapper3 # inner3 = wrapper3(index) def index(): # 被裝飾對象 # inner1 ---》 print(‘from index...‘) # 正在装饰 # inner3 = wrapper3(index) # inner2 = wrapper2(inner3) # inner1 = wrapper1(inner2) ‘‘‘ inner1() inner2() inner3() index() ‘‘‘ index() # 此处执行 # inner1() --> inner2() ---> inner3()
无参装饰器:装饰被装饰对象时,没有传参数的装饰器
有参数装饰器:装饰被装饰对象时,有传参数的装饰器,如:wrapper(参数)
# 无参装饰器: 装饰在被装饰对象时,没有传参数的装饰器。 ‘‘‘ # 以下是无参装饰器 @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_role): # ‘SVIP‘ def wrapper(func): def inner(*args, **kwargs): if user_role == ‘SVIP‘: print(‘超级用户‘) # 添加超级用户的功能 res = func(*args, **kwargs) return res elif user_role == ‘普通用户‘: print(‘普通用户‘) # 添加普通用户的功能 res = func(*args, **kwargs) return res return inner return wrapper # 被装饰对象 # @user_auth(‘SVIP‘) #wrapper = user_auth(‘普通用户‘) #@wrapper @user_auth(‘SVIP‘) # wrapper = user_auth(‘普通用户‘) # @wrapper #<--- 返回结果(wrapper) <---- user_auth() def index(): pass index()
wraps:
是一个修复工具,修复的是被装饰对象的空间。
###from functools import wraps
‘‘‘ wraps: (了解) 是一个修复工具,修复的是被装饰对象的空间。 from functools import wraps ‘‘‘ from functools import wraps def wrapper(func): @wraps(func) # 修改名称空间: inner ---》 func def inner(*args, **kwargs): ‘‘‘ 此处是装饰器的注释 :param func: :return: ‘‘‘ res = func(*args, **kwargs) return res return inner # ---》 func @wrapper def index(): ‘‘‘ 此处是index函数的注释 :return: ‘‘‘ pass print(index) # 函数对象 # 函数对象.__doc__: 查看函数内部的注释 print(index.__doc__) # inner.__doc__
二、迭代器
迭代器是迭代取值的工具
迭代:迭代指的是重复迭代,每一次迭代都是基于上一次的结果而来
如果想要知道Python中迭代器是什么,必须先要知道什么是可迭代对象。
可迭代对象:所有序列类型:str,list, tuple, dict,set,f
凡是内部有__iter__()f方法都是可迭代类型,如:list__iter__()
获取迭代器:
通过可迭代对象.__iter__()得到的返回值就是‘迭代器对象’
迭代器是迭代取值的工具,作用就是迭代取值
如何取值:
迭代器对象.__next__() #每执行一次就会取出一个对象
list1 = [1, 2, 3, 4] iter_list1 = list1.__iter__() #返回迭代器对象 print(iter_list1.__next__()) #每执行一次就会取出一个对象 print(iter_list1.__next__()) print(iter_list1.__next__()) print(iter_list1.__next__()) print(iter_list1.__next__()) #当可迭代对象内部没有对象时再取就会报错 结果: 1 2 3 4 File "/Users/tophan/python练习/day12/迭代器.py", line 7, in <module> print(iter_list1.__next__()) StopIteration
迭代器对象的优点:
1、不依赖索引迭代取值
2、节省空间
迭代器对象缺点:
1、取指定的某个值麻烦
2、每次取值都要从第一个值开始,无法通过索引取值。
#文件即是可迭代对象,也是迭代器对象,因为文件从读取出来就是迭代器对象
***可迭代对象不一定是迭代器对象
迭代器对象一定是可迭代对象
# x = 10 # while True: # print(x) # # list1 = [1, 2, 3, 4] # 1, 2, 3, 4 # n = 0 # while n < len(list1): # print(list1[n]) # n += 1 # 以下都是可迭代对象 ‘‘‘ str1 = ‘hello tank!‘ str1.__iter__() list1 = [1, 2, 3] # list([1, 2, 3]) list1.__iter__() set.__iter__() dict.__iter__() tuple.__iter__() open(‘a.txt‘).__iter__() ‘‘‘ # str1 = ‘靓仔靓女‘ # iter_str1 = str1.__iter__() # print(iter_str1) # iterator指的是迭代器对象 # iter_str1 ---> 靓仔,靓女! # print(iter_str1.__next__()) # print(iter_str1.__next__()) # print(iter_str1.__next__()) # print(iter_str1.__next__()) # 因为迭代器中的值已经取完了 # print(iter_str1.__next__()) # 报错,StopIteration dict1 = {‘age‘: 17, ‘name‘: ‘tank‘} iter_dict1 = dict1.__iter__() print(iter_dict1.__next__()) print(iter_dict1.__next__()) # print(iter_dict1.__next__())
补充:
不依赖索引的取值方式
tuple1 = (‘tank‘, ‘jason鸡哥‘, ‘sean‘, ‘饼哥‘)
# 获取迭代器对象: iter_list1
iter_tuple1 = tuple1.__iter__()
while True:
# 补充: try: 捕获异常
try:
print(iter_tuple1.__next__()) # 报错
# 立即触发此处代码 StopIteration
except StopIteration:
break
for 循坏内部原理:
for 循坏在工作时,首先会调用可迭代对象goods内置的_iter_方法拿到一个迭代器对象,
然后再调用该迭代器对象的__next__方法将取到的值赋给item,执行循坏体,周而复始,
直到捕捉到Stopliteration异常,结束迭代。
以上是关于叠加装饰器与迭代器的主要内容,如果未能解决你的问题,请参考以下文章