生成器是python一個比較高級的特性,理解也比較抽象
產生生成器的方法有幾種:
第一種
a=(i for i in range(10))
print(a) # ----- generator object <genexpr> at 0x0000022BD830E410
print(type(a)) # ---- generator
這時候a變成了一個生成器
(注:使用a=[i for i in range(10)]會產生一個列表,注意區分[]和()的區別)
第二種:使用yield關鍵字
def foo():
yield 1
a=foo()
使用關鍵字yield,也可以將函數變成生成器
生成器有next(python2爲next()方法)和send()方法
可以看到,每次我們調用next()方法時,都會返回下一個值
然後下次調用再從上次結束的地方繼續調用
這樣做的好處是不用返回一整個列表,非常節省字符空間
比如在python2環境中,有range和xrange兩個方法(在python3中取消了xrange,直接使用range,相當於python3的rangge就是python2的xrange方法)
xrange就是一個迭代器
在python2的環境中運行
sum(x for x in range(100000000))
可以觀察電腦資源使用情況,我這CPU直接100%,內存%100,直接重啓了
因爲range是一次生成1-100000000的列表
而sum(x for x in xrange(100000000))可以看到系統資源基本沒有什麼佔用
因爲xrange是一次次地調用值,所以資源佔用少
生成器函數send
next其實就是send(None)
def count(n):
for i in range(n):
yield i
a=yield i
print(a)
gen=count(5)
gen.send(“test”)則會打印出test
可以看到gen.next()和gen.send(None)效果是一樣的
其實next源碼就是send(None)的實現
另外gen.close()方法即爲關閉生成器,再調用next會拋出StopIteration異常
既然 send裏面的值可以傳給(yield),那麼我們可以用這個來實現簡單的簡單的生產消費者,也是簡單協程的實現
def consumer():
i = 0
while True:
tmp = yield i
if tmp is not None:
print("我是消費者: {}".format(tmp))
def producer(gen, n):
gen.__next__()
for i in range(n):
print("我是生產者: {}".format(i))
gen.send(i)
gen = consumer()
producer(gen, 5)