Python基础之迭代器、生成器
一、迭代器:
1、迭代:每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。例如:循环获取容器中的元素。
2、可迭代对象(iterable):
1)定义:具有__iter__函数的对象,可以返回迭代器对象。
2)语法:
3)原理:
3、迭代器对象(iterator):
1)定义:可以被next()函数调用并返回下一个值的对象。
2)语法:
3)说明及作用:
二、生成器(generator):
三、生成器函数:
6、内置生成器:
7、生成器表达式:
四、基础代码:
代码1:
""" 可迭代对象:具有__iter__()方法,可以返回迭代器的对象. """ list01 = [2,434,5,6,8] # for item in list01: # print(item) # 面试题: # 能够被for循环的条件是:可迭代对象(具有__iter__()方法的对象) # for循环原理 # 1. 获取迭代器对象 # 2. 循环迭代(调用迭代器的__next__方法) # 3. 捕获StopIteration异常 #1. # iterator = list01.__iter__() #2. # item = iterator.__next__() # print(item) # # item = iterator.__next__() # print(item) # # item = iterator.__next__() # print(item) # # item = iterator.__next__() # print(item) # # item = iterator.__next__() # 最后一次 # print(item) # 3. # item = iterator.__next__()# StopIteration # print(item) # 1. 获取迭代器对象 iterator = list01.__iter__() while True: try:# 如果获取了全部元素,则执行except # 2. 获取下一个元素(迭代过程) item = iterator.__next__() print(item) # 3.停止迭代(StopIteration 错误) except StopIteration: break # 跳出循环体
代码2:
""" 迭代器 """ class Skill: pass class SkillIterator: """ 技能迭代器 """ def __init__(self, target): self.target = target self.index = 0 def __next__(self): # 如果索引越界 则抛出异常 if self.index > len(self.target) - 1: raise StopIteration() # 返回下一个元素 item = self.target[self.index] self.index += 1 return item class SkillManager: """ 可迭代对象 """ def __init__(self, skills): self.skills = skills def __iter__(self): # 创建迭代器对象 传递 需要迭代的数据 return SkillIterator(self.skills) #---------------以下是客户端代码--------------------- manager = SkillManager([Skill(), Skill(), Skill()]) # for item in manager.skills: for item in manager:# 获取manager对象中列表元素(获取manager对象的聚合类型对象元素) print(item) # iterator = manager.__iter__() # while True: # try: # item = iterator.__next__() # print(item) # except: # break
代码3:
""" 迭代器 --> yield """ class Skill: pass # class SkillIterator: # """ # 技能迭代器 # """ # def __init__(self, target): # self.target = target # self.index = 0 # # def __next__(self): # if self.index > len(self.target) - 1: # raise StopIteration() # item = self.target[self.index] # self.index += 1 # return item class SkillManager: def __init__(self, skills): self.skills = skills # def __iter__(self): # return SkillIterator(self.skills) def __iter__(self): """ 执行过程: 1.调用__iter__()方法不执行 2.调用__next__()方法时执行,到yield语句暂时离开. 3.再次调用__next__()方法时,从上次离开的代码开始执行,到yield语句暂时离开 4. 待执行完方法体,抛出StopIteration异常. 原理:如果方法体中包含yield关键字,那么会自动生成迭代器对象. 生成迭代器代码的大致规则: 1. 将yield关键字以前的代码,放到__next__方法中. 2. 将yield关键字以后的数据,作为__next__方法的返回值 """ # print("准备返回第一个元素") # yield self.skills[0] # 暂时离开点 再次执行点 # # print("准备返回第二个元素") # yield self.skills[1] # # print("准备返回第三个元素") # yield self.skills[2] for item in self.skills: yield item #---------------以下是客户端代码--------------------- manager = SkillManager([Skill(), Skill(), Skill()]) # for item in manager: # print(item) iterator = manager.__iter__() while True: try: item = iterator.__next__() print(item) except Exception as e: print(e) break
代码4:
""" yield --> 生成器函数 """ # class MyRange: # def __init__(self, stop): # self.stop = stop # # def __iter__(self): # start = 0 # while start < self.stop: # yield start # start += 1 # # for item in MyRange(5): # print(item) # 生成器函数 def my_range(stop): start = 0 while start < stop: yield start start += 1 # for item in my_range(5): # print(item) iter01 = my_range(5) for item in iter01: print(item)
代码5:
""" 内置生成器:enumerate """ list01 = ["a", "b", "c"] for item in enumerate(list01): # (索引,元素) print(item) for index, element in enumerate(list01): print(index, element) # 练习:参照上述代码,自定义函数,my_enumerate. # 10:46 def my_enumerate(target): index = 0 for item in target: yield (index,item) index += 1 for item in my_enumerate(list01): print(item) for index, element in my_enumerate(list01): print(index, element)
代码6:
""" 内置生成器:zip """ list02 = [101,102,103] list03 = ["张三丰","张无忌","赵敏"] for item in zip(list02,list03): # (101, '张三丰') print(item) #练习:参照上述代码,自定义函数,my_zip 11:05 def my_zip(list01,list02): for index in range(len(list01)): # yield (list01[index],list02[index]) yield list01[index], list02[index] for item in my_zip(list02,list03): # (101, '张三丰') print(item)
代码7:
""" 生成器表达式 """ list01 = [2,3,4,6] # result = [] # for item in list01: # result.append(item ** 2) # 列表推导式[] 字典推导式 {键:值 for ...} 集合 { for ... } result = [item ** 2 for item in list01] print(result) # def fun01(target): # for item in target: # yield item ** 2 # 生成表达式 # for item in fun01(list01): # print(item) result = (item ** 2 for item in list01) for item in result: print(item)
五、练习实例:
练习1:
# 练习1:("悟空","八戒","沙僧","唐僧") # 使用while + 迭代器 获取元组所有元素 t01 = ("悟空", "八戒", "沙僧", "唐僧") iterator = t01.__iter__() while True: try: item = iterator.__next__() print(item) except: break # 练习2:{"张三丰":101,"张无忌":102,"赵敏":102} # 不使用for循环,获取字典所有元素. d01 = {"张三丰": 101, "张无忌": 102, "赵敏": 102} iterator = d01.__iter__() while True: try: key = iterator.__next__() print(key, d01[key]) except: break
练习2:
""" 练习:迭代员工管理器对象 """ class Employee: pass class EmployeeIterator: """ 迭代器 """ def __init__(self, target): self.target = target self.index = 0 def __next__(self): if self.index > len(self.target) - 1: raise StopIteration() item = self.target[self.index] self.index += 1 return item # 可迭代对象 class EmployeeManager: def __init__(self, employees): self.all_employee = employees def __iter__(self): # 返回迭代器 return EmployeeIterator(self.all_employee) manager = EmployeeManager([Employee(), Employee()]) # 需求:for循环自定义类的对象 # for item in manager: # print(item) # iterator = manager.__iter__() while True: try: item = iterator.__next__() print(item) except: break
练习3:
""" 参照下列代码,定义MyRange类,实现相同效果. """ # 15:40 class MyRangeIterator: def __init__(self, stop): self.stop = stop self.start = 0 def __next__(self): if self.start + 1 > self.stop: raise StopIteration() temp = self.start self.start += 1 return temp class MyRange: def __init__(self, stop): self.stop = stop def __iter__(self): # 创建迭代器对象 return MyRangeIterator(self.stop) # for item in range(5): # print(item)# # for item in MyRange(5): # print(item)#0 1 2 3 4 iterator = MyRange(5) for item in iterator: print(item) # # iterator = iterator.__iter__() # while True: # try: # item = iterator.__next__() # print(item) # except: # break
练习4:
""" 改造为yield实现 """ class Employee: pass # class EmployeeIterator: # """ # 迭代器 # """ # def __init__(self, target): # self.target = target # self.index = 0 # # def __next__(self): # if self.index > len(self.target) - 1: # raise StopIteration() # item = self.target[self.index] # self.index += 1 # return item # 可迭代对象 class EmployeeManager: def __init__(self, employees): self.all_employee = employees # def __iter__(self): # # 返回迭代器 # return EmployeeIterator(self.all_employee) def __iter__(self): for item in self.all_employee: yield item manager = EmployeeManager([Employee(), Employee()]) # 需求:for循环自定义类的对象 # for item in manager: # print(item) # iterator = manager.__iter__() while True: try: item = iterator.__next__() print(item) except: break
练习5:
""" 改造为yield实现 """ # class MyRangeIterator: # def __init__(self, stop): # self.stop = stop # self.start = 0 # # def __next__(self): # if self.start + 1 > self.stop: # raise StopIteration() # temp = self.start # self.start += 1 # return temp class MyRange: def __init__(self, stop): self.stop = stop # def __iter__(self): # # 创建迭代器对象 # return MyRangeIterator(self.stop) def __iter__(self): start = 0 while start < self.stop: yield start start += 1 iterator = MyRange(5) # for item in iterator: # print(item) # iterator = iterator.__iter__() while True: try: item = iterator.__next__() print(item) except: break
练习6:
""" 生成器函数练习 体会:方法/函数,需要向外返回多个结果时,使用生成器函数. 惰性操作/延迟操作 (生成器函数的"循环(next)一次,计算一次,返回一次") """ list01 = [23,3,4,556,677,68,8,98,98] # 练习1:在list01中,挑出所有偶数. # 要求:1)使用生成器函数实现 def get_even01(target): for item in target: if item % 2 == 0: yield item iter01 = get_even01(list01)# 没有执行方法体 for item in iter01:# 循环(next)一次,计算一次,返回一次 print(item) # def get_even02(target): # result = [] # for item in target: # if item % 2 == 0: # result.append(item) # return result # # iter01 = get_even02(list01)# 执行方法体,将所有结果存在内存中. # for item in iter01: # print(item) # 练习2:定义函数,选出所有女同学. class Student: def __init__(self,name,sex,age,score): self.name = name self.sex = sex self.age = age self.score = score def __str__(self): return "%s--%s--%d--%d"%(self.name,self.sex,self.age,self.score) list_stu = [ Student("张无忌","男",28,82), Student("赵敏","女",25,95), Student("周芷若","女",26,88), ] def find_woman(target): for item in target: if item.sex == "女": yield item for item in find_woman(list_stu): print(item) # 练习3:选出所有成绩大于90的学生 def find_by_score(target): for item in target: if item.score > 90: yield item for item in find_by_score(list_stu): print(item)
练习7:
# 1.创建技能类(编号,技能名称,冷却时间,攻击力,消耗法力) # 创建技能列表. # -- 定义函数:查找编号是101的技能对象 # -- 定义函数:查找冷却时间为0的所有技能对象 # -- 定义函数:查找攻击力大于5的所有技能对象 # -- 定义函数:查找攻击力大于10,并且不需要消耗法力的所有技能. class SkillData: def __init__(self, id, name, cd, atk, costSP): self.id = id self.name = name self.cd = cd self.atk = atk self.costSP = costSP list_skills = [ SkillData(101, "降龙十八掌", 60, 10, 5), SkillData(102, "如来神掌", 50, 15, 0), SkillData(103, "六脉神剑", 0, 20, 8), SkillData(104, "一阳指", 0, 50, 15), SkillData(105, "冷酷追击", 15, 30, 9), ] # 因为需要查找的结果只有一个,所以使用return返回数据. # 比使用yield返回数据,在调用者看来,更加方便吧. def find_demo01(target): for item in target: if item.id == 101: return item s01 = find_demo01(list_skills) print(s01.id) def find_demo02(target): for item in target: if item.cd == 0: yield item result = find_demo02(list_skills) # 不能获取指定结果 # 因为:此时生成器函数并没有计算处结果. # print(result[1].name) # for item in result: # print(item.name) result = find_demo02(list_skills) # 通过生成器创建列表 # 由惰性查找(优势:节省内存) 转换为 立即查找(优势:灵活获取结果) result = list(result) # print(result[1].name) def find_demo03(target): for item in target: if item.atk > 5: yield item # 调用生成器函数,创建迭代器对象 result = find_demo03(list_skills) for item in result:# __next__() print(item.name) print("---------------") # 如果没有下一行代码,再次for使用过的生成器对象,不会再有结果. # result = find_demo03(list_skills) for item in result: print(item.name) # for item in find_demo03(list_skills): # .... def find_demo04(target): for item in target: if item.atk > 10 and item.costSP == 0: yield item for item in find_demo04(list_skills): print(item.name)
练习8:
list02 = [2,3,4,6] # 练习:使用列表推导式,与生成器表达式,获取list02中,大于3的数据. result01 = [item for item in list02 if item > 3 ] # 本行代码:执行所有操作,保存所有结果 result02 = (item for item in list02 if item > 3 ) # 本行代码:返回生成器对象 for item in result01:# 从结果中获取数据 print(item) for item in result02:# 循环一次,计算一次,返回一次 print(item)
练习9:
# 1.创建技能类(编号,技能名称,冷却时间,攻击力,消耗法力) # 创建技能列表. # -- 定义函数:查找冷却时间为0的所有技能对象 # -- 定义函数:查找攻击力大于5的所有技能对象 # -- 定义函数:查找攻击力大于10,并且不需要消耗法力的所有技能. # 使用列表推导式,与生成器表达式完成 # 通过断点调试,审查程序执行过程,体会两项技术的差异. class SkillData: def __init__(self, id, name, cd, atk, costSP): self.id = id self.name = name self.cd = cd self.atk = atk self.costSP = costSP def __str__(self): return self.name list_skills = [ SkillData(101, "降龙十八掌", 60, 10, 5), SkillData(102, "如来神掌", 50, 15, 0), SkillData(103, "六脉神剑", 0, 20, 8), SkillData(104, "一阳指", 0, 50, 15), SkillData(105, "冷酷追击", 15, 30, 9), ] # def find_demo02(target): # for item in target: # if item.cd == 0: # yield item result01 = (item for item in list_skills if item.cd == 0) result02 = [item for item in list_skills if item.cd == 0] for item in result01: print(item) for item in result02: print(item) # def find_demo03(target): # for item in target: # if item.atk > 5: # yield item result01 = (item for item in list_skills if item.atk > 5) result02 = [item for item in list_skills if item.atk > 5] for item in result01: print(item) for item in result02: print(item) # def find_demo04(target): # for item in target: # if item.atk > 10 and item.costSP == 0: # yield item result01 = (item for item in list_skills if item.atk > 10 and item.costSP == 0) result02 = [item for item in list_skills if item.atk > 10 and item.costSP == 0] for item in result01: print(item) for item in result02: print(item)