Python基础(7)——迭代器&生成器

时间:2023-03-10 08:51:14
Python基础(7)——迭代器&生成器

1、列表生成式

 [i*2 for i in range(10)]
[fun(i) for i in range(10)]

2、生成器

 # Author Qian Chenglong

 #列表生成器
a=(i*2 for i in range(10))
#a[1]#只是将算法存储了,只有在调用时才会生成相应的数据,不能直接读取
a.__next__()#生成器只能一个一个往后取,且只存储当前值 #函数生成器 # def fib(max):
# n,a,b = 0,0,1
# while n < max:
# print(b)
# a,b = b,a+b
# n += 1
# return 'done' #要把fib函数变成generator,只需要把print(b)改为yield b就可以了
def fib(max):
n,a,b = 0,0,1
while n < max:
#print(b)
yield b
a,b = b,a+b
n += 1
return 'done'#异常时存储的消息 g=fib(10)
print(g.__next__())
#这个yield的主要效果呢,就是可以使函数中断,并保存中断状态,中断后,代码可以继续往下执行,过一段时间当需要再重新调用这个函数,从上次yield的下一句开始执行。 #生成器保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误(异常)。 #异常处理
g = fib(6)
while True:
try:
x = next(g)
print('g:', x) except StopIteration as e:
print('Generator return value:', e.value)
break #通过生成器实现协程并行运算
import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了2个包子!")
c.send(i)
c2.send(i)#把i的值传给yield,并到下一个yield producer("Dragon")

3、迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是否是Iterable对象:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

  一般来说:生成器就是迭代器,迭代器不一定是生成器(下面不用看了,越看越不懂)

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成Iterator可以使用iter()函数:

 >>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。