生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写 __iter__() 和 __next__() 方法了,只需要一个 yiled 关键字。
首先迭代提供的嵌套列表中的所有字列表,然后按顺序迭代自列表中的元素。任何包含yield语句的函数称为生成器。除了名字不同意外,它的行为和普通函数也有很大的差别,这就在于它不像return那样返回值,而是每次产生多个值。每次产生一个值(使用yield语句),函数就会被冻结:即函数停在那点等待被激活,函数被激活后就从停止的那点开始执行
- nested=[[1,2],[3,4],[5]]
- def flatten(nested):
- for sublist in nested:
- for element in sublist:
- yield element
- for num in flatten(nested):
- print(num)
- #1
- # 2
- # 3
- # 4
- # 5
- print(list(flatten(nested)))#[1, 2, 3, 4, 5]
- 生成器两种创建方式1. (x * 2
- for x in range(3))
- # a=[x*2 for x in range(1000000)]#不要试,死机
- s=(x*2 for x in range(3))
- print(s)#<generator object <genexpr> at 0x00000203201E6938>
- print(next(s)) #等价于print(s.__next__()),in Py2: s.next()
- print(next(s))print(next(s))
- print(next(s))#StopIteration
- # 生成器就是一个可迭代对象(iterable)
- 2.yield 生成器对象
- 生成器是一个包含yield关键字的函数。当它被调用时,在函数体中的代码不会执行,而会返回一个迭代器。每次请求一个值,就会执行生成器中的代码,知道遇到yield或者return语句。
- yield语句意味着应该生成一个值,return语句意味着生成器要停止执行(不再生成任何东西,return语句只有在一个生成器中使用时才能进行无参数调用),换句话说生成器又两部分组成:生成器的函数和生成器的迭代器生成器的函数使用def语句定义,包含yield,生成器的迭代器是这个函数返回的部分。
按一种不是很准确的说法,两个实体经常被当做一个,合起来叫做生成器。生成器函数跟普通函数只有一点不一样,就是把 return 换成yield,其中yield是一个语法糖,内部实现了迭代器协议,同时保持状态可以挂起。
- def foo():
- print("Hello world")
- yield 1
- print("ok")
- yield 2
- foo()#生成器对象,不会执行代码
- g=foo()
- print(g)#<generator object foo at 0x00000230A33569E8>
- next(g) #Hello world
- next(g) #ok
- # next(g)#StopIteration
- for i in foo():#遍历可迭代对象,对象拥有iter方法
- print(i)
- #Hello world
- # 1
- # ok
- # 2
用生成器来实现斐波那契数列的例子:一
- def fib(max):
- n, a, b = 0, 0, 1
- while n < max:
- # print(b)
- yield b
- a, b = b, a + b
- n = n + 1
- return 'done'
- f=fib(6)
- print(f)#<generator object fib at 0x0000025839E56990>
- #这里,最难理解的就是generator和函数的执行流程不一样。
- # 函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
- # 而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,
- # 再次执行时从上次返回的yield语句处继续执行。
- print(f.__next__())
- print(f.__next__())
- print("________*****______")
- print(f.__next__())
- print(f.__next__())
- print(f.__next__())
- 结果:
1
1
________*****______
2
3
5
二
- def fib(max):
- n, a, b = 0, 0, 1
- while n < max:
- # print(b)
- yield b
- a, b = b, a + b
- n = n + 1
- return 'done'
- f=fib(6)
- while True:
- try:
- x=next(f)
- print('f:',x)
- except StopIteration as e:
- print("Generator return value:",e.value)
- break
- #结果
- f: 1
- f: 1
- f: 2
- f: 3
- f: 5
- f: 8
- Generator return value: done
生成器新属性是在开始运行后为生成器提供值的能力。表现为生成器和“外部世界”进行交流的渠道:
- def bar():
- print('ok1')
- count=yield 1
- print(count)
- yield 2
- b=bar()
- next(b)
- # s=b.send(None)#next(b) 第一次send前如果没有next,只能传一个send(None)
- # print(s)
- ret=b.send('eee')
- print(ret)
- # b.send('fff')
- 结果:
ok1
eee
2
- send工作方法
- def f():
- print("ok")
- s=yield 7
- print(s)
- yield 8
- f=f()
- print(f.send(None))
- # ok
- # 7
- print(next(f))
- # None
- # 8
- #print(f.send(None))等同于print(next(f)),执行流程:打印ok,yield7,当再next进来时:将None赋值给s,然后返回8,可以通过断点来观察
吃包子案例
- 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("%s开始准备做包子啦!"%name)
- for i in range(1,6,2):
- time.sleep(1)
- print("做了2个包子!")
- c.send(i)
- c2.send(i+1)
- producer("greg")
协程应用:
所谓协同程序也就是是可以挂起,恢复,有多个进入点。其实说白了,也就是说多个函数可以同时进行,可以相互之间发送消息等。
- import queue
- def tt():
- for x in range(3):
- print ('tt'+str(x) )
- yield
- def gg():
- for x in range(3):
- print ('xx'+str(x) )
- yield
- class Task():
- def __init__(self):
- self._queue = queue.Queue()
- def add(self,gen):
- self._queue.put(gen)
- def run(self):
- while not self._queue.empty():
- for i in range(self._queue.qsize()):
- try:
- gen= self._queue.get()
- gen.send(None)
- except StopIteration:
- pass
- else:
- self._queue.put(gen)
- t=Task()
- t.add(tt())
- t.add(gg())
- t.run()
- # tt0
- # xx0
- # tt1
- # xx1
- # tt2
- # xx2
来源: http://www.cnblogs.com/gregoryli/p/7820433.html