多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# 迭代器 [参考][1] ## 迭代器协议 由于生成器自动实现了迭代器协议,而迭代器协议对很多人来说,也是一个较为抽象的概念。所以,为了更好的理解生成器,我们需要简单的回顾一下迭代器协议的概念。 * 迭代器协议是指:对象需要提供`next`方法,它要么返回迭代中的下一项,要么就引起一个`StopIteration`异常,以终止迭代 * 可迭代对象就是:实现了迭代器协议的对象 * 协议是一种约定,可迭代对象实现迭代器协议,Python的内置工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。 ## 可迭代对象 Iterable 直接作用于for循环的数据类型有以下几种: * 一类是集合数据类型,如list、tuple、dict、set、str等; * 一类是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 可以使用`isinstance()`判断一个对象是否是Iterator对象: ~~~ >>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False ~~~ ## 使用iter()将列表转化为迭代器 ## 为什么使用迭代器 这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。 Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。 --- # 生成器 [参考][2] 生成器的元素在创建时,并没有真正的产生;创建时只是指向了生成器的内存地址 * 这是一种惰性计算 * 生成器只能遍历一次 ## Python的生成器 * 语法上和函数类似:生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值 * 自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的`next`方法,并且,在没有值可以返回的时候,生成器自动产生`StopIteration`异常 * 状态挂起:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行 ### 生成器表达式 ~~~ >>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x1022ef630> ~~~ ### 生成器函数 ~~~ def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a,b = b,a+b n += 1 ~~~ for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获`StopIteration`错误,返回值包含在StopIteration的value中: ~~~ >>> g = fib(6) >>> while True: ... try: ... x = next(g) ... print('g:', x) ... except StopIteration as e: ... print('Generator return value:', e.value) ... break ... g: 1 g: 1 g: 2 g: 3 g: 5 g: 8 Generator return value: done ~~~ ## 特性 * 只有next方法,若元素为空时会报错, * 不能进行通过索引进行引用和切片 * 只能通过**for**来调用 ## 执行顺序 函数是顺序执行,遇到return语句或者最后一行函数语句就返回。 而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。 ## 通过生成器实现并发运算 协程 ~~~ #coding: utf8 import time def consumer(name): print("%s 准备吃包子" %name) while True: print "before " + "name:" + name baozi = yield baozi = baozi + "name:" + name print "after " + "name:" + name print "包子[%s]来了,被谁[%s]吃了" % (baozi, name) def producer(name): a = consumer('a') b = consumer('b') a.next() b.next() print("%s开始做包子" % name) for i in range(1): time.sleep(3) print("做了一个包子") a.send("1") b.send("2") producer('yang') ~~~ send用于给生成器传递数据 ![](http://om4h63cja.bkt.clouddn.com/17-9-3/38538377.jpg) [1]:http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html [2]:http://www.cnblogs.com/huxi/archive/2011/07/14/2106863.html