在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次调用。

12-20 07:02