迭代器和生成器
本篇我们介绍可迭代对象和迭代器对象--包括两者的定义及区别、为什么要有迭代器对象,其的用法是怎么样的 和 for循环的机制,当然还有生成器的介绍,这里还会介绍列表生成器,三元运算式等。
1、迭代器对象
1、迭代器协议
①迭代器协议:对象需要提供__next__方法,它要么返回迭代中的下一项,要么就引起StopIteration异常,以终止迭代。
②可迭代对象:实现了迭代器协议的对象(如何实现-->对象内部有__iter__的内置方法。)
③协议:可迭代对象实现迭代器协议,Python内置工具(如for循环、max、nin、sum函数等)使用迭代器协议访问可迭代对象。
2、可迭代对象和迭代器对象
可迭代对象(iterable):该对象内有__iter__()内置方法,为可迭代对象。还有一种说法是可以被for循环遍历的对象为可迭代对象。
可迭代对象常见的有两类: ①->某些数据类型,例如:str、list、tuple、dict、set等,以及其调用iter()方法得到的迭代器对象。 ②->generatot生成器对象。包括生成器表达式、yield生成器函数。 当然还有一些其他的对象也是迭代器对象,例如,f=open("test.txt","r",encoding="utf-8"), f 也为可迭代对象。 |
迭代器对象(iterator):该对象内不仅有__iter__()方法,还有__next__()内置方法,则为迭代器对象。也有的说-->可以调用__next__()内置方法并且不断返回下一个值或者异常的对象,称为迭代器对象。
所以说:迭代器对象包含迭代器对象,即迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象。
例如:
#可迭代对象和迭代器对象
lis1=["zhangsan","lisi","wangwu"] #可迭代对象
# iter_lis1=lis1.__iter__() #迭代器对象
iter_lis1=iter(lis1) # ==> 等同于iter_lis1=lis1.__iter__()
print(type(lis1),type(iter_lis1))
#迭代器对象可以不断的调用__next__()内置方法,并且返回下一个值或者异常
print(iter_lis1.__next__()) #zhangsan
print(iter_lis1.__next__()) #lisi
print(iter_lis1.__next__()) #wangwu
print(iter_lis1.__next__()) #StopIteration,异常
3、那为什么需要迭代器呢?
有两个方面:
一、迭代器的主要优点呢就是支持延迟计算,不需要你事先准备好整个需要迭代的数据,而在此之前元素可以不存在或者销毁,这种特性使它使用一个巨大的或者无线的集合,只要实现了__iter__就可以使用迭代器访问了可迭代对象,就可以使用iter()方法使可迭代对象变为迭代器而迭代器中的__next__会返回下一个迭代对象。简单来说:节约内存空间,方便使用。
二、对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器。
#对于序列可以使用索引遍历序列中每个值 lis2=["zhangsan","lisi","wangwu"] index=0 while index<len(lis2): print(lis2[index]) index+=1 #然而对于非序列,这种方法则无法实现,则需要使用到迭代器 set2={"zhangsan","lisi","wangwu"} i =0 iter_set2=set2.__iter__() #转换为迭代器对象 while i<len(set2): print(iter_set2.__next__()) i+=1
4、for循环的机制
不废话直接看示例:
#for循环机制 #for循环内部的处理方式 lis4=["zhangsan","lisi","wangwu","alex"] iter_lis4=lis4.__iter__() while True: try: print(iter_lis4.__next__()) except StopIteration: break #等同于 lis3=["zhangsan","lisi","wangwu","alex"] for i in lis3: print(i)
其实不止是for循环,还有max函数、sum函数等,均是将可迭代对象先通过iter()内置函数或者__iter__()内置方法转换为迭代器对象。随后通过不断地进行while循环,通过__next__()方法获取可迭代对象中的下一个值。而当遇到异常StopIteration便终止循环。
2、生成器
在了解生成器时,我们将生成器分为两种类型,即生成器表达式、带yield的生成器函数。
2.1 生成器表达式
在了解生成器表达式之前,我们需要先了解一下列表生成式以及三元表达式。
2.1-1 三元表达式
其形式为:为真时候的结果 if 判断条件 else 为假时候的结果。接下来我们用案例来看一下:
#三元表达式 #若我想获得->除了我女神外其他的都丑 name="amanda" res="Beautiful" if name=="amanda" else "Ugly" #三元表达式 print("She is %s ."%res)
2.1-2列表生成式
python中,列表生成式是用来创建列表的,相较于用循环实现更为简洁。举个例子,生成[1*1, 2*2, ... , 10*10],循环用三行:
lis=[] for i in range(10): lis.append(i**3)
而使用列表生成式,则一行就搞定:前面是生成规则,后面是初始元素,最后还可以加上判断条件:
lis=[ i**3 for i in range(10) ]
当然列表生成式还可以实现多层循环,以及判断:
#若我想做1-5,5-10中的偶数两两做乘法运算 lis1=[a*b for a in range(1,5) for b in range(5,10) if a%2==0 and b%2==0] print(lis1) #输出为:[12, 16, 24, 32]
那么生成器表达式又是怎么样的呢?
其实将列表生成式的方括号变为圆括号即为生成器表达式。例如
#生成器表达式,该例->获取1-10中3的倍数的3次幂 lis=(i**3 for i in range(10) if i%3==0) print(lis) #输出结果为:<generator object <genexpr> at 0x00000222219BED58>
2.2 生成器函数
生成器函数:只需要把函数的return语句变成yield即可,yield将函数的返回值存入在生成器对象中,可以通过__next__()方法不断的取出下一个值,直到遇到StopIteration异常,终止调用。
#生成器函数 def test(): for i in range(5): yield i**2 yield i**3 #yield不同于return,可以在一个函数内多次使用,并且将值添加至生成器对象中 g=test() #调用函数,得到生成器对象 print(g) #结果为:<generator object test at 0x000001E03E04ED58> print(list(g)) #[0, 0, 1, 1, 4, 8, 9, 27, 16, 64] #也可以通过不断调用__next__方法获得下一个值 print(g.__next__()) print(g.__next__())
完成。想到什么在补充。->Little-five原创,当然也参考了别人的博客。
本文来自博客园,作者:Little_five,转载请注明原文链接:https://www.cnblogs.com/littlefivebolg/articles/9102173.html