在Python中, 一边循环一边计算后面元素的机制称为生成器 generator
一、列表生成器
语法:
a = [i+1 for i in rang(10)]
print(a)
[1,2,3,4,5,6,7,8,9,10]
二、生成器
语法:
把列表生成器中的中括号 [] 换成 () 即可
例:
(x*x for x in range(10))生成的就是一个生成器。
如果要一个一个打印出来,可以通过next()
函数获得generator的下一个返回值:
generator保存的是算法,每次调用next(g)
就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
当然,上面这种不断调用next(g)
实在是太变态了,正确的方法是使用for
循环,因为generator也是可迭代(遍历)对象:
>>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)
...
0
1
4
9
16
25
36
49
64
81
三、函数生成器
def feib(n):
a = 0
b = 1
count = 0
while count < n:
tmp = a
a = b
b += tmp
#print(b)
yield b # 暂停,程序执行到这里,就会暂停到这里,返回b到函数外面,直到被next方法调用时才会唤醒
count += 1
f = feib(10) # 注意这句调用时,函数并不会被执行,只有下一次调用next方法时,函数才会真正被执行
print(next(f))
print(next(f))
print("----暂停一下还能继续往下走----")
print(next(f))
四、并发编程
通过yield, 我们可以实现单核下并发做多件事的效果
例:
def consumer(name):
print("消费者%s准备吃包子了" % name)
baozi = yield # 此处的yield接收外部send传过来的数据并赋值给baozi
print("消费者%S收到第%s批包子" %(name,baozi))
c1 = consumer(c1)
c2 = consumer(c2)
c3 = consumer(c3)
c1.__next()__ # 执行一下next才能使上面的函数走到yield那句,这样后面的send语法才能生效
c2.__next()__
c3.__next()__
for i in range(1,10)
print("-----生产了第%s批包子-----" % i )
c1.send(i) # send的作用=next,同时把数据i传给上面函数的yield
c2.send(i)
c3.send(i)
输出结果:
消费者c1准备吃包子了
消费者c2准备吃包子了
消费者c3准备吃包子了
--------生产了第1批包子-------
消费者c1收到第1批包子
消费者c2收到第1批包子
消费者c3收到第1批包子
--------生产了第2批包子-------
消费者c1收到第2批包子
消费者c2收到第2批包子
消费者c3收到第2批包子
--------生产了第3批包子-------
消费者c1收到第3批包子
消费者c2收到第3批包子
消费者c3收到第3批包子
--------生产了第4批包子-------
消费者c1收到第4批包子
消费者c2收到第4批包子
消费者c3收到第4批包子
--------生产了第5批包子-------
消费者c1收到第5批包子
消费者c2收到第5批包子
消费者c3收到第5批包子
--------生产了第6批包子-------
消费者c1收到第6批包子
消费者c2收到第6批包子
消费者c3收到第6批包子
--------生产了第7批包子-------
消费者c1收到第7批包子
消费者c2收到第7批包子
消费者c3收到第7批包子
--------生产了第8批包子-------
消费者c1收到第8批包子
消费者c2收到第8批包子
消费者c3收到第8批包子
--------生产了第9批包子-------
消费者c1收到第9批包子
消费者c2收到第9批包子
消费者c3收到第9批包子
注意:调用send(x)给生成器传值时,必须确保生成器已经执行过一次next()调用, 这样会让程序走到yield位置等待外部第2次调用。