python 基础 day04—列表生成器/生成器
列表生成式
a=[i*2 for i in range(10)] print(a) #==> [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
若不用列表生成式,可用以下方法达到以上效果
for i in range(10): a.append(i*2) print(a)
比较复杂!
生成器
1.只有在调用时才会生成相应的数据
2.只记录当前位置
3.只有一个__next__方法
创建一个生成器,只要把一个列表生成式的[]
改成()
,就创建了一个generator
( i*2 for i in range(10) )
现在,用函数写斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到
def fib(max): n,a,b=0,0,1 while n < max: print(b) a,b=b,a+b n=n+1 return 'done' #出现异常的时候打印的消息 print(fib(10)) 结果: 1 1 2 3 5 8 13 21 34 55 done #所有消息均输出完毕,因此抛出异常消息
可以看出,fib
函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
要把fib
函数变成generator,只需要把print(b)
改为yield b
就可以了
通过函数做成一个生成器
def fib(max): n,a,b=0,0,1 while n < max: yield(b) #yield的作用是保存当前状态,然后返回 a,b=b,a+b n=n+1 return 'done' f= fib(10) print(a) print(f.__next__()) #输出f当前值 print(f.__next__()) print("休息一下") print(f.__next__()) print(f.__next__()) print("===从这里开始for循环==") for i in f: print(i)
结果:
<generator object fib at 0x03671230> 1 1 休息一下 2 3 ===从这里开始for循环== 5 8 13 21 34 55
最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return
语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
下面我们尝试通过生成器实现协程并行运算
先来个前奏
def consumer(name): print("%s 准备吃包子!" %name) while True: baozi=yield #程序走到yield然后返回 print("包子[%s]来了,被[%s]吃了!"%(baozi,name)) c=consumer("Cherry") c.__next__() #调用生成器 c.__next__() 结果: Cherry 准备吃包子! 包子[None]来了,被[Cherry]吃了! #因为没有包子,所以显示none
因此,我们给做个包子
def consumer(name): print("%s 准备吃包子!" %name) while True: baozi=yield #yield作用是保持当前状态然后返回,直到下次执行时从这里继续执行 print("包子[%s]来了,被[%s]吃了!"%(baozi,name)) c=consumer("Cherry") c.__next__() #调用生成器 baozi1="荠菜猪肉馅" a.send(baozi1) #send给yield赋值,然后yield传值给baozi 结果: Cherry 准备吃包子! 包子[荠菜猪肉馅]来了,被[Cherry]吃了!
完整的正餐!
#_*_coding:utf-8_*_ import time def consumer(name): print("%s 准备吃包子!" %name) while True: baozi=yield print("包子[%s]来了,被[%s]吃了!"%(baozi,name)) def producer(name): c=consumer('A') #c是name为A的一个生成器 c2=consumer('B') #c2是name为A的一个生成器 c.__next__() #执行c的第一步操作 c2.__next__() #执行c2的第一步操作 print("开始做包子!") for i in range(3): time.sleep(2) print("做了两个包子") c.send(i) #执行c的下一步操作,把i传值给yield c2.send(i) producer("Cherry") 结果: A 准备吃包子! B 准备吃包子! 开始做包子! 做了两个包子 包子[0]来了,被[A]吃了! 包子[0]来了,被[B]吃了! 做了两个包子 包子[1]来了,被[A]吃了! 包子[1]来了,被[B]吃了! 做了两个包子 包子[2]来了,被[A]吃了! 包子[2]来了,被[B]吃了!