python详解(9)--python中的多任务(协程与迭代器和生成器)

一、python中的迭代器与生成器

可迭代对象 Iterable
将可以通过迭代工具(如for,list(),tuple()等)迭代的对象称为可迭代对象Iterable,可以通过collections.abc中的Iterable类,使用isinstance(a, Iterable)来判断a是否为可迭代对象,所有的iterable都是Iterable类的继承类的实例,所有的可迭代对象都支持__iter__方法。

迭代器 Iterator
迭代器是一个实现了迭代器协议的对象,任何的可迭代对象都支持的__iter__()方法就将可迭代对象转换为迭代器对象,使用isinstance(object,abc.Iterator)来判断对象是否是迭代器对象,所有的迭代器都支持__next__()方法,迭代器最核心的功能就是将原本的序列转换为惰性的。
迭代器的作用:①为遍历不同的聚合结构提供一个统一的接口;②访问一个聚合对象的内容而无需暴露它的内部表示。

迭代(for循环,list转换等)的作用流程
①检测被迭代对象是否是Iterable,若是则调用其__iter__()方法将其转换为Iterator,若已经是Iterator则跳过此步,若以上两者都不是则抛出异常;
②对Iterator调用其__next__()方法返回序列的第一个元素,对其进行操作(若是list转换则将元素加进列表),重复此操作直至处理完序列的所有元素;
③当元素处理完后,__next__方法会抛出StopIteration异常,此时迭代工具会捕捉此异常并进行处理,然后停止迭代,返回结果。

:①Iterable与Iterator是两种不同的类型,Iterable支持__iter__方法不支持__next__方法,Iterator支持__next__方法不支持__iter__方法;
②双下划线的方法为魔法方法,其可以使用obj.__next__()方式调用也可以直接以next(obj)的方式调用;
③迭代器对象是可迭代对象的转换,其允许将数据分批读取防止爆内存,但迭代器对象一经迭代就耗尽,若要继续使用必须重新生成;
④打开文件的字节流即是Iterable也是Iterator。

生成器 generator
python中的生成器是一种特殊的迭代器,首先其满足迭代器的所有功能和特性,其次生成器是在序列的生成上进行了改进。
迭代器一般是由可迭代对象转换而来(也可以自定义迭代器,但相对繁琐),因此其序列内容往往是事先固定的,而生成器简单来说,就是保存了序列中元素产生的方法,在需要的时候根据这个方法生成元素,因此节省了大量的存储空间,与迭代器类似的,生成器一经迭代就销毁。

生成器的创建方法
①元组推导式
列表、字典、集合推导式都是直接根据传入的函数和参数产生对象并将其转换好后返回,而元组推导式产生的是一个生成器,对于生成器(迭代器)来说,其不会显式的将序列的元素表示出来,只有调用其next方法时才会抛出序列的第一个元素,后续与迭代器相同,不再赘述(在很多情况下,并不区分迭代器与生成器);
②yield关键字
yield关键字是一个类似于return的关键字,其在函数中的作用为:当next方法被调用时,将当前值返回,然后阻塞等待,直到下一次next被调用时,函数回复它刚刚脱离的位置(即yield语句的位置,记忆最后一次执行的位置和所有的数据值)并继续执行直到下一个yield。
使用yield关键字的函数就是一个生成器,这个生成器序列中的元素就是yield返回的值,每调用一次next,函数就运行一段,直到yield语句,然后阻塞等待。

yield生成器的注意事项
①yield生成器中可以存在return语句,当执行至return时,生成器对象抛出StopIteration异常,会将return后的内容作为异常的详细信息显示;
②next方法操作生成器方法与上述迭代器相同,其返回值就是yield后的内容,在生成器中还存在send方法,send方法只有obj.send('aa')这一种调用方式,其作用为给yield语句本身赋值,常用于在迭代过程中改变生成器对象,例如:

def f():
	while True:
		res = yield 1
		if res == 3:
			yield 2

此时就可以使用send(3)来使生成器的下一个元素改为2,注意send()不能对一个还没有使用next语句的生成器使用,但是send(None)可以,即若是一个新生成器,第一次迭代时若使用send方法则必须obj.send(None)

:①对迭代器进行切片操作,使用标准库中的itertools.islice,它能返回一个迭代对象切片的生成器,islice(obj, start, end),其也是一个迭代工具,即会消耗掉迭代器对象;
②迭代器和生成器一经使用就销毁,必须重新生成,不能重复利用;
③与返回值类似的,生成器和迭代器对象的传递的是引用和方法,如果一个生成器对象yield一个可变对象(如yield一个列表,则在生成器对象中传递的都是引用,此时使用list,a.append()等不直接表明值的方法,其产生的列表会重复),则其值很可能会重叠为最后一个,这是python中可变对象的陷阱,一定要注意,在return/yield一个可变对象(尤其还是以变量引用的形式)时要格外小心
生成器保存的是生成元素的方法,这句话是正确理解生成器用法的最关键的注意事项,例如:

def primes1():
	yield 2
	it = list()
	n = 2
	for i in range(5):
		yield i
		it.append(lambda x: x+i)
	yield it

那么保存在此生成器序列中的匿名函数是相同的,虽然占用了不同的内存,但是其生成方法就是lambda x: x+i,在调用时,会自动去各级命名空间中寻找i,最终找到i=4,因此对于该生成器中的匿名函数而言,其形式就是lambda x: x+4,此问题与③中情况有区别也有联系,应着重分析。
python详解(4)–函数一文中,对于reduce函数的举例其结果会出现错误,其原理即上述分析过程,优化方式即将当前的n同步传入匿名函数,有兴趣可自行测试结果。

二、同步/异步/阻塞/非阻塞与IO模型

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值