[ python ] 迭代器和生成器
列表生成式
列表生成式是 python 内置的非常简单却强大的可以用来创建list的生成式。
有这样一个需求:
l1 = [1,2,3,4,5,6,7,8,9] 循环每个元素加1
1 2 3 4 5 | l1 = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] # 使用列表生成式将列表中的各个元素加1 list_num = [x + 1 for x in l1] # 这里就是一个列表生成式 print (list_num) |
列表生成式可以用一行语句代替循环生成上面的list
迭代器
迭代器表面上看是一个数据流对象或容器,当使用其中的数据时,每次从数据流中取出一个数据,直到数据被取完,而且数据不会被重复使用。
从代码的角度来看,迭代器是实现了迭代器协议方法的对象和类。
迭代器协议方法主要是两个:
__iter__(): 该方法返回对象本身,它是for语言使用迭代器的要求,只要函数含有__iter__就可以说这个函数是可迭代的;
__next__(): 该方法用于返回容器中下一个元素或数据。当容器中的数据用尽时,应该引发 StopIteration 异常一个类只要具有这两种方法,就可以称之为 迭代器,也可以说是可迭代的。
1 2 3 4 5 6 7 8 9 | s1 = 'hello world' print ( '__iter__' in dir (s1)) print ( '__next__' in dir (s1)) # 字符串s1包含 __iter__ 方法且不包含__next__方法,所以字符串 s1 只是一个可迭代的类型,并不是一个迭代器 # 执行结果: # True # False |
1 2 3 4 5 6 7 8 9 | s1 = 'hello world' s2 = s1.__iter__() # 将可迭代类型转换为 迭代器 使用 __iter__() print ( '__iter__' in dir (s2)) print ( '__next__' in dir (s2)) # 使用 __iter__()方法将 s1 字符串转换为迭代器,迭代器既有__iter__方法,又有 __next__方法 # 执行结果: # True # True |
自定义一个迭代器必须满足:
类中必须要定义 __iter__ 方法和 __next__方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # 自定义一个迭代器: class My_iterator( object ): def __init__( self , x, max ): self .mul, self .x = x, x self .xmax = max def __iter__( self ): return self def __next__( self ): if self .x and self .x ! = 1 : self .mul = self .mul + self .x if self .mul < self .xmax: return self .mul else : raise StopIteration if __name__ = = '__main__' : myite1 = My_iterator( 2 , 100 ) for i in myite1: print (i) |
迭代器一定是可迭代的, 但是可迭代的不一定是迭代器
生成器
使用生成器可以生成一个值的序列用于迭代,并且这个值的序列不是一次生成的,而是使用一个,再生成一个,可以使得程序节约大量内存。
生成器对象是通过yield关键字定义的函数对象,因此生成器也是一个函数。生成器用于生成一个值的序列,以便在迭代中使用。
自定义生成器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def foo(): print ( '1111' ) yield 1 print ( '22222' ) yield 2 f = foo() print ( 'type f:' , type (f)) print (f.__next__()) print (f.__next__()) # 执行结果: # type f: <class 'generator'> # 1111 # 1 # 22222 # 2 |
执行流程如下图:
需要注意的是 yield 是生成器中的关键字,生成器在实例化的时候并不会立即执行,而是等待调用其__next__()方法之后才开始运行,当再次调用__next__()方法会在第一次yield返回值的最后开始执行,不断的调用__next__()方法,直到最终返回 StopIteration 异常为止。
实例1:移动平均值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 移动平均值 def foo(): ''' sum 计算总和 count 计算有几个数 avg 平均数 :yield: 返回计算出的平均数 ''' sum = 0 count = 0 avg = 0 while True: num = yield avg # 接收num,返回avg sum += num count += 1 avg = sum / count f = foo() next(f) ret = f.send(10) print(ret) ret = f.send(20) print(ret) ret = f.send(30) print(ret) ret = f.send(40) print(ret) # 执行结果: # 10.0 # 15.0 # 20.0 # 25.0
本文作者:hukey
本文链接:https://www.cnblogs.com/hukey/p/9698150.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步