列表生成式:是代碼更簡潔.
也可以是函數,比如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用的也是這個方法