Python迭代与生成器
迭代
每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。例如:循环获取容器中的元素。
可迭代对象iterable
1.定义:具有__iter__函数的对象,可以返回迭代器对象。
2.语法
-- 创建:
class 可迭代对象名称:
def __iter__(self):
return 迭代器
-- 使用:
for 变量名 in 可迭代对象:
语句
3.原理:
迭代器 = 可迭代对象.__iter__()
while True:
try:
print(迭代器.__next__())
except StopIteration:
break
1 list01 = [43,4,54,5,566,7,7] 2 # for itme in list01: 3 # print(itme) 4 5 #对象具有__iter__()方法 6 7 # for原理: 8 # 1. 获取迭代器对象 9 iterator = list01.__iter__() 10 # 2. 循环获取下一个元素 11 while True: 12 try: 13 item = iterator.__next__() 14 print(item) 15 # 3. 异常处理 16 except StopIteration:# 迭代完成 17 break
迭代器对象iterator
1.定义:可以被next()函数调用并返回下一个值的对象。
2.语法
class 迭代器类名:
def __init__(self, 聚合对象):
self.聚合对象= 聚合对象
def __next__(self):
if 没有元素:
raise StopIteration
return 聚合对象元素
3.说明:聚合对象通常是容器对象。
4. 作用:使用者只需通过一种方式,便可简洁明了的获取聚合对象中各个元素,而又无需了解其内部结构。
1 class SkillIterator: 2 """ 3 迭代器 4 """ 5 6 def __init__(self, target): 7 self.target = target 8 self.index = 0 9 10 def __next__(self): 11 # 需求:将SkillManager中__list_skill的元素返回 12 # 创建一个下标索引index,与列表的长度比较,要求下表索引不能超过列表的长度 13 if self.index > len(self.target) - 1: 14 raise StopIteration() 15 # 下标每次+1,并将每次下标元素返回去 16 result = self.target[self.index] 17 self.index += 1 18 return result 19 20 21 class Skill: 22 pass 23 24 class SkillManager: 25 def __init__(self): 26 self.__list_skill = [] 27 28 def add_skill(self, skill): 29 self.__list_skill.append(skill) 30 31 def __iter__(self): 32 return SkillIterator(self.__list_skill) 33 34 35 manager = SkillManager() 36 manager.add_skill(Skill()) 37 manager.add_skill(Skill()) 38 manager.add_skill(Skill()) 39 40 41 iterator = manager.__iter__() 42 while True: 43 try: 44 item = iterator.__next__() 45 print(item) 46 except StopIteration: 47 break
1 class Skill: 2 pass 3 4 5 class SkillManager: 6 """ 7 可迭代对象 8 """ 9 10 def __init__(self): 11 self.__list_skill = [] 12 13 def add_skill(self, skill): 14 self.__list_skill.append(skill) 15 16 def __iter__(self): 17 # return SkillIterator(self.__list_skill) 18 19 for item in self.__list_skill: 20 yield item 21 22 """ 23 执行过程: 24 1. 调用__iter__()方法程序不执行. 25 2. 调用__next__()方法开始执行. 26 3. 执行到yield语句暂时离开方法. 27 4. 再次调用__next__()方法继续执行 28 ..... 29 原理:如果方法体中包含yield语句,则自动生成迭代器代码. 30 生成迭代器代码的大致规则: 31 1.将yield关键字以前的代码,放到__next__()方法中. 32 2.将yield关键字以后的数据,作为__next__()方法返回值. 33 """ 34 35 # print("准备第一个元素:") 36 # yield self.__list_skill[0] 37 # 38 # print("准备第二个元素:") 39 # yield self.__list_skill[1] 40 # 41 # print("准备第三个元素:") 42 # yield self.__list_skill[2] 43 44 45 manager = SkillManager() 46 manager.add_skill(Skill()) 47 manager.add_skill(Skill()) 48 manager.add_skill(Skill()) 49 50 51 iterator = manager.__iter__() 52 while True: 53 try: 54 item = iterator.__next__() 55 print(item) 56 except StopIteration: 57 break
1 tuple01 = (4, 4, 5, 565, 6, 7) 2 iterator = tuple01.__iter__() 3 while True: 4 try: 5 item = iterator.__next__() 6 print(item) 7 except: 8 break
1 dict01 = {"张无忌":3,"赵敏":2} 2 iterator = dict01.__iter__() 3 while True: 4 try: 5 key = iterator.__next__() 6 value = dict01[key] 7 print(key,value) 8 except: 9 break
生成器generator
1.定义:能够动态(循环一次计算一次返回一次)提供数据的可迭代对象。
2.作用:在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。
3.以上作用也称之为延迟操作或惰性操作,通俗的讲就是在需要的时候才计算结果,而不是一次构建出所有结果。
生成器函数
1.定义:含有yield语句的函数,返回值为生成器对象。
2.语法
-- 创建:
def 函数名():
…
yield 数据
…
-- 调用:
for 变量名 in 函数名():
语句
1 class MyGenerator: 2 """ 3 备注:本类是生成器的"源码",只需要看,不需要写. 4 生成器:可迭代对象 + 迭代器对象 5 """ 6 7 def __init__(self, stop_value): 8 self.__stop_value = stop_value 9 self.__start_value = 0 10 11 def __iter__(self): 12 return self 13 14 def __next__(self): 15 if self.__start_value >= self.__stop_value: 16 raise StopIteration() 17 result = self.__start_value 18 self.__start_value += 1 19 return result 20 21 22 def my_range(stop_value): 23 start_value = 0 24 while start_value < stop_value: 25 yield start_value 26 start_value += 1 27 28 29 # 0 1 2 3 4 30 result = my_range(5) 31 # 生成器对象.__iter__() 返回的结果就是生成器对象 32 # 140573829693376 33 print(id(result.__iter__())) 34 # 140573829693376 35 print(id(result)) 36 37 # 函数体包含yield语句,返回值类型是生成器. 38 print(type(result)) 39 #<class 'generator'> 40 for item in result: 41 print(item)
3.说明:
-- 调用生成器函数将返回一个生成器对象,不执行函数体。
-- yield翻译为”产生”或”生成”
4.执行过程:
(1) 调用生成器函数会自动创建迭代器对象。
(2) 调用迭代器对象的__next__()方法时才执行生成器函数。
(3) 每次执行到yield语句时返回数据,暂时离开。
(4) 待下次调用__next__()方法时继续从离开处继续执行。
5.原理:生成迭代器对象的大致规则如下
-- 将yield关键字以前的代码放在next方法中。
-- 将yield关键字后面的数据作为next方法的返回值。
1 def get_even(list_target): 2 for item in list_target: 3 if item % 2 == 0: 4 # return item 返回一个数据,退出方法. 5 yield item # 返回多个数据,暂时离开方法 6 7 8 list01 = [34, 4, 54, 5, 7, 8] 9 result = get_even(list01) 10 # print(result) 11 # 没有事先存储所有偶数, 12 # 而是循环一次 计算一次 返回一次 13 for item in result: 14 print(item)
内置生成器
枚举函数enumerate
1.语法:
for 变量 in enumerate(可迭代对象):
语句
for 索引, 元素in enumerate(可迭代对象):
语句
2.作用:遍历可迭代对象时,可以将索引与元素组合为一个元组。
1 def my_enumerate(list_target): 2 for i in range(len(list_target)): 3 yield (i, list_target[i]) 4 5 for item in my_enumerate([3,34,4,5,6]): 6 print(item) 7 8 for index,item in enumerate([3,34,4,5,6]): 9 print(index,item)
zip
1.语法:
for item in zip(可迭代对象1, 可迭代对象2….):
语句
2.作用:将多个可迭代对象中对应的元素组合成一个个元组,生成的元组个数由最小的可迭代对象决定。
1 def my_zip(list01,list02): 2 for i in range(len(list01)): 3 yield (list01[i] ,list02[i]) 4 5 for item in my_zip([2,4,45],[5,6,8]): 6 print(item) 7 #(2, 5) 8 #(4, 6) 9 #(45, 8) 10 list01 = ["张无忌","赵敏","周芷若"] 11 list02 = [101,102] 12 for item in zip(list01,list02,list02): 13 print(item) 14 #('张无忌', 101, 101) 15 #('赵敏', 102, 102)
生成器表达式
1.定义:用推导式形式创建生成器对象。
2.语法:变量 = ( 表达式 for 变量 in 可迭代对象 [if 真值表达式] )
list01 = [4,4,5,56,6,78] # 立即执行,将所有结果存入内存 result01 = [item for item in list01 if item >5] for item in result01: print(item) # 56 6 78 result02 = (item for item in list01 if item >5) # 延迟执行,循环一次 计算一次 返回一个(覆盖了上一个) for item in result02: print(item) #56 6 78
总结:
(1)迭代器,生成器是什么?
1.迭代器是一个更加抽象的概念,任何对象,如果他的类有next方法和iter方法返回自身.对于string,list,dict,tuple等这类容器对象,使用for循环遍历是很方便的.在后台for语句对容器对象调用了iter()函数,iter()是python的内置函数.iter()会返回一个定义了next()方法的迭代器对象,他在容器中逐个访问容器内元素,next()也是python的内置函数在没有后续元素时,next()会排除一个Stoplterration的异常.
2.生成器是创建迭代器的简单而强大的工具,只是在返回数据的时候需要使用yield语句.每次next()被调用时,生成器就会返回他脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
(2)他们的区别?
生成器一次只返回一个值,降低内存消耗,而迭代器一次返回所有值.
生成器能做到迭代器能做的所有事,而且因为自动创建了 __ iter __ ()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存,除了创建和保持程序状态的自动生成,当生成器终结时,也会自动抛出Stoplterration的异常