迭代器和生成器
本节导读:
- 可迭代对象
- 迭代器
- 可迭代和迭代器的区别
- 判断迭代器和可迭代对象的方法
- 生成器
一 可迭代对象
什么叫迭代?:一个一个取值,就像for循环一样取值
可以直接作用于for
循环的对象统称为可迭代对象:Iterable,有以下两类
- 一类是集合数据类型,如
list
、tuple
、dict
、set
、str
等; - 一类是
generator
,包括生成器和带yield
的generator function。
迭代器协议:可以被迭代要满足要求的就叫做可迭代协议。内部实现了__iter__方法
二 迭代器
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator,其内部实现了__iter__,__next__方法,
迭代器大部分都是在python的内部去使用的,我们直接拿来用就行了
迭代器的优点:如果用了迭代器,节约内存,方便操作
三 可迭代和迭代器的相同点和不同点
都可以用for循环,迭代器内部多实现了一个__next__方法
四判断迭代器和可迭代对象的方法
第一种:判断内部是不是实现了__next__方法
'__iter__' in dir(str)#如果__iter__在这个方法里面,就是可迭代的。
第二种:
Iterable 判断是不是可迭代对象
Iterator 判断是不是迭代器
from collections import Iterable from collections import Iterator #比如给一个字符串 s='abc' print(isinstance(s,Iterable))#isinstance判断类型的 print(isinstance(s,Iterator)) #判断range和map函数 map1=map(abs,[1,-2,3,-4]) print(isinstance(map1,Iterable)) print(isinstance(map1,Iterator))#map方法自带迭代器 s=range(100)#是一个可迭代的,但是不是迭代器 print(isinstance(s,Iterable)) print(isinstance(s,Iterator))
五 生成器
列表生成式
# ======一层循环====== l = [i*i for i in range(1,10)] print(l) # 上面的列表推倒式就相当于下面的 l = [] for i in range(1,10): l.append(i*i) print(l) l = [] # ======多层循环======== # 1.列表推倒式 l = [i*j for i in range(1,10) for j in range(1,10)] print(l) # 2.循环 l = [] for i in range(1,10): for j in range(1,10): s = i*j l.append(s) print(l)
通过列表生成式,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
生成器不必创建完整的list,通过next()方法随用随取,从而节省大量的空间。
生成器的创建
- 生成器表达式
只要把一个列表生成式的[]
改成(),
- yield生成器函数,
遇到yeild,函数就冻结,并返回yeild后面的值,同过next()方法,使函数继续从yeild之后执行
如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用次方法来实现。
yield函数:
- send 用法
def test(): for i in range(10): ret = yield print('这是send发送的结果',ret) a = test() next(a) # 在send数据前必须要先next一下,不然会报错 a.send('asdf')
- yield from 用法
def func(): # for i in 'AB': # yield i yield from 'AB' yield from 'AB'就相当于上面的for循环,吧循环简化了 yield from [1,2,3] g=func() print(list(g)) # print(next(g)) # print(next(g))
你可能会问,为什么list
、dict
、str
等数据类型不是Iterator
?
这是因为Python的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
Python3的for
循环本质上就是通过不断调用next()
函数实现的