列表生成式:是代码更简洁.
也可以是函数,比如func(i)
生成器:generator
列表生成式,是中括号,改成小括号,就是生成器:
如果你用列表生成式,生成一亿个数据:这里会卡好久,会生成一亿个数据到内存里去。
而用生成器,立马会得到生成器的内存地址,不需要等待:
但是要注意,生成器c不允许使用下标的方式,进行取值。因为循环还没计算到这个值。
- 生成器只有在调用时才会生成相应的数据;
- 生成器有一种方法c.__next__(),来取下一个值,只有下一个next,没办法返回上一个值。它每次只保留一个值;
- 只记录当前位置;
- 只有一个方法__next__()方法。在py2里,生成器的下一个方法的写法是next()
现在我们用另外一种方法来创建一个生成器:
fib(10)代表max生成10个数列,a代表第一个值,b代表第二个值,n表示循环10次
这里很容易混淆,大家一定要注意!!!
结果如下:
这个时候,我们把print(b)替换为yield b,yield是产量的意思,这个时候,这个fib()就是生成器了
yield的作用,就是中断状态,就是返回当前状态的值,并且函数停在这个位置。yield在第一次next的时候,函数执行到yield就返回,(yield之前的程序执行完,yield后面的就不执行了!),紧接着第二次next的时候,首先,函数会继续执行yield后面的程序,然后继续执行循环,直至执行到yield之前的函数!!!如此反复。
而且。这个fib(100)这个生成器非常牛逼,可以用f.__netxt__()的方式,随时调用函数fib(),随时执行,调用一次以后可以去干别的时候,回头再来执行一次。这个就是生成器的牛逼之处!!!
如果你不用for循环,一直用__next__()方法,就会超过数值,这个时候会报错,出一个异常代码StopIteration:done
注意函数里的return '---done---',那么在报错的打印中就也会返回这个return这个字符串:
return在这里的作用就是异常的时候打印的东西。
我们现在要对异常做处理:我们要抓住异常状态用try...except StopIteration来处理
只要出的错误是StopIteration,那么下面的代码就可以抓住,然后做相应的处理:
在 try里用next(生成器)的写法跟__next__()方法是一样的效果。
生成器还有一个牛逼的用法,实现多线程的并行效果:
这个是一个典型的生产者消费者模型,一个人生产包子,一个吃包子:
首先我们牢记,yield的作用,就是中断状态,就是返回当前状态的值,并且函数停在这个位置。yield在第一次next的时候,函数执行到yield就返回,(yield之前的程序执行完,yield后面的就不执行了!),紧接着第二次next的时候,首先,函数会继续执行yield后面的程序,然后继续执行循环,直至执行到yield之前的函数!!!如此反复。
我们这里发现用__next__()不会给yield传值,但是send(变量)可以相当于是__next__(),而且给yield传值了!
我们再看生产者的代码:
上面的这个方法也叫异步,也叫协程,nginx用的也是这个方法