迭代器和生成器
迭代器
迭代的概念
迭代就是重复的过程,每重复一次就是一次迭代,并且每次迭代的结果作为下一次迭代的初始值。
#不是迭代,只是重复 while True: p = input('>>:') print p
#迭代,每次循环基于上一次的返回值 l = [1,2,3,4] t = 0 while t < len(l): print(l[t]) t += 1
可迭代对象
为了提供一种不依赖于索引的迭代方式,python会为一些对象内置
__iter__方法。python中,字符串、列表、元组、字典、集合、文
件都是可迭代对象。
判断是否为可迭代对象可以导入Iterable模块__iter__
from collections import Iterable f = open('a.txt','w') f.__iter__() # 下列数据类型都是可迭代的对象 print(isinstance('abc',Iterable)) # 字符串 print(isinstance([1,2,3],Iterable)) # 列表 print(isinstance({'a':1,},Iterable)) # 字典 print(isinstance({1,2,3},Iterable)) # 集合 print(isinstance((1,2,),Iterable)) # 元组 print(isinstance(f,Iterable)) # 文件 # 输出: True True True True True True
迭代器
判断是否是迭代器导入Iterator模块:
from collections import Iterable,Iterator f = open('a.txt','w') # 只有文件是迭代器对象 print(isinstance('abc',Iterator)) print(isinstance([],Iterator)) print(isinstance((),Iterator)) print(isinstance({'a':1},Iterator)) print(isinstance({1,2},Iterator)) print(isinstance(f,Iterator)) # 输出: False False False False False True
从上面可以看出只要文件是迭代器对象。迭代器对象具有__iter__方法和__next__方法。上面讲的可迭代对象obj.__iter__()得到的结果就是迭代器。
迭代器的优点:
提供了一种不依赖于索引的取值方式
惰性计算。节省内存
迭代器的缺点:
取值不如按照索引取值方便
一次性的。只能往后走不能往前退
无法获取长度
迭代器取值
# for循环取值 l = ['tom',12,'jack',16] i = l.__iter__() # i此时成为了迭代器对象 for k in i: print(k) #执行结果: tom 12 jack 16
# __next__方法取值 l = ['tom',12,'jack',16] i = l.__iter__() print(i.__next__()) print(i.__next__()) print(i.__next__()) print(i.__next__()) #执行结果: tom 12 jack 16
使用__next_()取值时,迭代到最后会抛出StopIteration的异常,for循环可以捕捉StopIteration异常来终止迭代。如果使用while循环可以使用如try ... except ...
while True: try: k = i.__next__() #也可以直接使用k = next(i) print(k) except StopIteration: break
扩展enumrate()
enumerate()方法生成的也是迭代器对象
l=[2,3,4] i=enumerate(l,1) print(i) for k in i: print(k) #执行结果 <enumerate object at 0x000001291540B318> (1, 2) (2, 3) (3, 4)
生成器
生成生成器(generator)
>>> g = (x * x for x in range(5)) >>> g <generator object <genexpr> at 0x000002C1CDF4D728>
上述中g就是一个生成器,生成器是迭代器对象,可以迭代取值:
g = (x * x for x in range(5)) print(g.__next__) print(g.__iter__) for i in g: print(i) #执行结果: <method-wrapper '__next__' of generator object at 0x00000202224A1D00> <method-wrapper '__iter__' of generator object at 0x00000202224A1D00> 0 1 4 9 16
上面讲了通过表达式子生成生成器,下面讲述下生成器函数,生成器函数也是生成器,也是迭代器对象。
def foo(): print('first') yield 1 print('second') yield 2 print('third') yield 3 g = foo() for i in g: print(i) #执行结果 first 1 second 2 third 3
简单分析上面执行,应该是每次迭代生成器函数foo()就执行一次函数,不过是遇到yield关键字就返回yield后面的值,直到没有yield关键字就抛出StopIteration异常。
yield的功能
与return类似,都可以返回值,但不一样的地方在于函数遇到return就退出函数不执行以后的内容,而yield返回值后不会退出,如果有下个yield就会执行到下个yield直到没有yiel。
为函数封装好了__iter__和__next__方法,把函数的执行结果做成了迭代器
遵循迭代器的取值方式obj.__next__(),触发的函数的执行,函数暂停与再继续的状态都是由yield保存的
详细分析生成器函数执行流程:
def foo(): print('in the foo ...') food = yield '您好' print('food >>>',food) print('我在后面') food1= yield '你坏' print('food1 >>> ',food1) g= foo() res = next(g) print(res) res1 = g.send('x') print(res1) ##res2= g.send('xx') ''' 生成器执行流程: 1.g=foo(),只是将foo()生成器对象赋值给g,然后继续往下执行; 2.遇到next()或g.send('x')就开始执行foo()内部的代码,\ 执行遇到第一个yield时,就暂停(我也理解为进入休眠状态),\ 并将yield后面的值返回给next(g),并跳出到foo()外面next(g)所在的那一行,\ 将yield返回的值赋值给res 3.res接收yield返回给next(g)的值,然后往下执行代码,打印res的值; 4.当再次遇到next()或g.send('x')时,唤醒foo()继续从上次 \ 暂停的位置开始执行, 同时将g.send(‘x’)中的'x'发送 \ 给第一个yield,并赋值给food,然后继续往下执行; 5.当遇到第二个yield时,进入暂停(休眠),\ 同时将yield后面的值返回给g.send('x'),\ 跳出到g.send('x')所在的那一行,并将yield返回的值赋值给res1,\ 然后继续执行至结束。 注意: print(res1)后面没有代码了,此时foo()中的food1是空,\ 如果print(res1)后面再出现g.send('xx')代码,\ 才会将'xx'发送给第二个yield,并赋值给food1; 但是,foo()内部会从第二个yield那一行继续往下执行,\ 如果后面没有yield关键字了,程序就会抛出一个StopIteration异常。 '''
简单应用
模拟linux的tail -f file|grep 命令:
这个例子在书籍当中比较经典:
import time file = r'\...\a.txt' def tail(file): with open(file,'r',encoding='utf-8') as f: f.seek(0,2) #先将光标移动到文件末尾 while True: line = f.readline() if line: yield line else: time.sleep(0.5) def grep(line,pattern): #line传入tail执行后的参数,pattern就是grep的关键词语 for i in line: if pattern in i: yield i def print_content(cmd): #传入生成器参数,迭代打印内容 for k in cmd: print(k,end='') print_content(grep(grep(tail('a.txt'),'error'),'404')) #传入参数,类似tail -f a.txt|grep 'error'|grep '404'
来源:https://www.cnblogs.com/liao-lin/p/7029605.html