Python3基础-迭代器&生成器
本节内容
- 列表生成
- 生成器
- 迭代协议
- 可迭代对象&迭代器
列表生成
>>>a=[x*x for x in range(10)] >>>a [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
生成器(generator)概念
在python中为节约内存空间,对延迟操作提供了支持,所谓的延迟操作(惰性)即需要的时候才产生结果,而不是和List一样马上产生全部结果。
python两种方式提供生成器:
- 生成函数:用常规函数定义,使用 yield 内置方法返回结果而不是return,yield 一次只返回一个结果,再每个结果结束后,处于挂载状态,以便下次重离开的地方继续执行
- 生成表达式:类似列表生成,把 [] 换成 () 使用,返回的是一个生成器对象
生成函数
- ----在python中yield就是一个生成器,通过方法yield返回结果
- ----那么该函数就不再是普通函数,而是生成器函数。
- ----再没有要求生成器产生结果时,函数内不会被访问输出
def gen(n):
for i in range(n):
yield i*2 #通过方法yield返回结果
r=gen(5)
print(r)
print(r.__next__())
print(next(r))
结果:
<generator object gen at 0x1021e2db0>
runing
0
runing
2
#普通的列表生成器
def gen_1(n):
res=[]
for i in range(n):
res.append(i*2)
return res
r_1=gen_1(5)
print(r_1)
结果:
[0, 2, 4, 6, 8]
生成表达式
a=(x*x for x in range(10)) print(a) 结果: <generator object <genexpr> at 0x1020e2f10>
Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
>>>sum(x ** 2 for x in range(4)) 14
总结:
- 自动实现迭代器协议:在python中会自动实现迭代器协议,可以调用next(obj) ___next__() 方法去取值,如何到最后没有值返回时,抛出 StopIteration 异常
- 状态挂起:生成器使用yield 返回值,yield 方法保存生成器函数的状态,每次要求产生值时,回到 yield 挂起出继续下一个执行(在每次调用
next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行) - 第一次执行next(generator)时,会执行完yield语句后程序进行挂起,所有的参数和状态会进行保存。再一次执行next(generator)时,会从挂起的状态开始往后执行。在遇到程序的结尾或者遇到StopIteration时,循环结束。
- 可以通过generator.send(arg)来传入参数,这是协程模型。
- 可以通过generator.throw(exception)来传入一个异常。throw语句会消耗掉一个yield。可以通过generator.close()来手动关闭生成器。
- next()等价于send(None)
支持的方法:
close()
手动关闭生成器函数,后面的调用会直接返回StopIteration异常。
def g4():
yield 1
yield 2
yield 3
g=g4()
print(next(g))
g.close()
next(g) #关闭后,yield 2和yield 3语句将不再起作用
send()
生成器函数最大的特点是可以接受外部传入的一个变量,并根据变量内容计算结果后返回。
这是生成器函数最难理解的地方,也是最重要的地方,实现后面我会讲到的协程就全靠它了。
- send<<===>>yield send传入值给yield触发执行yield并挂起等待下一次执行
- 通过 g.send(None) 或者 next(g) 可以启动生成器函数
def gen():
value = 0
while True:
receive = yield value
if receive == 'e':
break
value = 'got: %s' % receive
print('ok ')
g = gen()
print(g.send(None))
print(g.send('aaa'))
print(g.send(3))
print(g.send('e'))#已经退出循环没有接收到yield返回值
结果:
0
got: aaa
got: 3
ok
StopIteration异常
throw()
用来向生成器函数送入一个异常,可以结束系统定义的异常,或者自定义的异常。
throw()后直接跑出异常并结束程序,或者消耗掉一个yield,或者在没有下一个yield的时候直接进行到程序的结尾。
def gen():
value = 0
while True:
try:
receive = yield value
if receive == 'e':
break
value = 'got: %s' % receive
except ValueError:
print('valueError!!!')
except TypeError:#异常判断
print('TypeError!!!')
print('ok ')
g = gen()
print(g.send(None))
print(g.send('aaa'))
g.throw(TypeError)#传入一个异常
print(g.send(3))
迭代器Iterable
我们已经知道,可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
可迭代对象:
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
可以使用isinstance()判断一个对象是否是Iterable对象:
from collections import Iterable #导入模块
print(isinstance([],Iterable))
print(isinstance((),Iterable))
print(isinstance({},Iterable))
print(isinstance('ABC',Iterable))
print(isinstance(100,Iterable))
结果:
True
True
True
True
False
迭代器
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
Iterable变成Iterator
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

浙公网安备 33010602011771号