迭代器和生成器

 

  本篇我们介绍可迭代对象和迭代器对象--包括两者的定义及区别、为什么要有迭代器对象,其的用法是怎么样的 和 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原创,当然也参考了别人的博客。

    

posted @ 2018-05-28 22:57  Little_five  阅读(863)  评论(0编辑  收藏  举报