生成器(英文名Generator),是一个可以像迭代器那样使用for循环来获取元素的函数。
生成器的出现(Python2.2+),实现了延时计算,从而缓解了在大量数据下内存消耗过猛的问题。
当你在PythonShell中敲入一个生成器对象,会直接输出generatorobject提示你这是一个生成器对象
>>>gen=(iforiinrange(5))>>>genat0x10cae50b0>2.如何创建生成器?使用列表推导式在上面已经演示过,正常我们使用列表推导式时是下面这样子,使用[],此时生成的是列表。
>>>mylist=[iforiinrange(5)]>>>mylist[0,1,2,3,4]而当你把[]换成(),返回的就不是列表了,而是一个生成器
>>>gen=(iforiinrange(5))>>>genat0x10cae50b0>使用yieldyield是什么东西呢它相当于我们函数里的return,但与return又有所不同。
当一个函数运行到yield后,函数的运行会暂停,并且会把yield后的值返回出去。
若yield没有接任何值,则返回None
yield虽然返回了,但是函数并没有结束
请看如下代码,我定义了一个generator_factory函数,当我执行gen=generator_factory()时,gen就是一个生成器对象
>>>defgenerator_factory(top=5):...index=0...whileindex>>gen=generator_factory()>>>gen3.生成器的使用从一个生成器对象中取出元素,和我们前面学过的通过切片访问列表中的元素不一样,它没有那么直观。
想要从生成器对象中取出元素,只有两种方法:
第一种方法:使用next方法一个一个地把元素取出来,如果元素全部取完了,生成器会抛出StopIteration的异常。
>>>gen=(xforxinrange(3))>>>genat0x1072400b0>>>>next(gen)0>>>next(gen)1>>>next(gen)2>>>next(gen)Traceback(mostrecentcalllast):File"",line1,inStopIteration第二种方法:使用for循环一个一个地迭代出来
>>>gen=(xforxinrange(3))>>>foriingen:...print(i)...0124.生成器的激活生成器对象,在创建后,并不会执行任何的代码逻辑。
想要从生成器对象中获取元素,那么第一步要触发其运行,在这里称之为激活。
方法有两种:
使用next():上面已经讲过
使用generator.send(None)
还以下面这段代码为例,可以看到gen.send(None)相当于执行了next(gen)
>>>defgenerator_factory(top=5):...index=0...whileindex>>>>>gen=generator_factory()>>>gen.send(None)index值为:01>>>gen.send(None)index值为:125.生成器的状态生成器在其生命周期中,会有如下四个状态
GEN_CREATED#生成器已创建,还未被激活
GEN_RUNNING#解释器正在执行(只有在多线程应用中才能看到这个状态)
GEN_SUSPENDED#在yield表达式处暂停
GEN_CLOSED#生成器执行结束
通过下面的示例可以很轻松地理解这一过程(GEN_RUNNING这个状态只有在多线程中才能观察到,这里就不演示啦)
>>>gen=(xforxinrange(2))>>>frominspectimportgetgeneratorstate>>>gen=(xforxinrange(3))>>>getgeneratorstate(gen)'GEN_CREATED'>>>>>>next(gen)0>>>getgeneratorstate(gen)'GEN_SUSPENDED'>>>next(gen)1>>>next(gen)Traceback(mostrecentcalllast):File"",line1,inStopIteration>>>getgeneratorstate(gen)'GEN_CLOSED'6.生成器的异常在最前面,我有定义了一个生成器函数。
defgenerator_factory(top=2):index=0whileindex在没有元素可返回时,我最后抛出了StopIteration异常,这是为了满足生成器的协议。
实际上,如果你不手动抛出StopIteration,在生成器遇到函数return时,会我自动抛出StopIteration。
请看下面代码,我将raiseStopIteration去掉后,仍然会抛出异常。