生成器(Generator)

一、什么是生成器

通過列表生成式瞒大,我們可以直接創(chuàng)建一個列表螃征。但是,受到內(nèi)存限制透敌,列表容量肯定是有限的盯滚。而且,創(chuàng)建一個包含100萬個元素的列表酗电,不僅占用很大的存儲空間魄藕,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數(shù)元素占用的空間都白白浪費(fèi)了撵术。所以背率,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢?這樣就不必創(chuàng)建完整的list寝姿,從而節(jié)省大量的空間交排。在Python中,這種一邊循環(huán)一邊計算的機(jī)制饵筑,稱為生成器:generator埃篓。

二、創(chuàng)建生成器的方法

1.將列表的 [ ] 改為()

下面為python快速生成列表:

>>> [x for x in range(5)]
[0, 1, 2, 3, 4]

若將 [ ] 改為()翻翩,則會創(chuàng)建一個生成器都许,可迭代對象

>>> gener=(x for x in range(5))
>>> next(gener)
0
>>> next(gener)
1
>>> next(gener)
2
>>> next(gener)
3
>>> next(gener)
4
>>> next(gener)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>

生成器保存的是算法,每次調(diào)用 next(G) 嫂冻,就計算出 G 的下一個元素的值胶征,直到計算到最后一個元素,沒有更多的元素時桨仿,拋出 StopIteration 的異常睛低。當(dāng)然,這種不斷調(diào)用 next() 實(shí)在是太變態(tài)了服傍,正確的方法是使用 for 循環(huán)钱雷,因為生成器也是可迭代對象。所以吹零,我們創(chuàng)建了一個生成器后罩抗,基本上永遠(yuǎn)不會調(diào)用 next() ,而是通過 for 循環(huán)來迭代它灿椅,并且不需要關(guān)心 StopIteration 異常套蒂。

2.使用yield關(guān)鍵字。

generator非常強(qiáng)大茫蛹。如果推算的算法比較復(fù)雜操刀,用類似列表生成式的 for 循環(huán)無法實(shí)現(xiàn)的時候,還可以用函數(shù)來實(shí)現(xiàn)婴洼。
比如骨坑,著名的斐波拉契數(shù)列(Fibonacci),除第一個和第二個數(shù)外柬采,任意一個數(shù)都可由前兩個數(shù)相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契數(shù)列用列表生成式寫不出來欢唾,但是,用函數(shù)把它打印出來卻很容易:

In [28]: def fib(times):
   ....:     n = 0
   ....:     a,b = 0,1
   ....:     while n<times:
   ....:         print(b)
   ....:         a,b = b,a+b
   ....:         n+=1
   ....:     return 'done'
   ....: 

In [29]: fib(5)
1
1
2
3
5
Out[29]: 'done'

仔細(xì)觀察警没,可以看出匈辱,fib函數(shù)實(shí)際上是定義了斐波拉契數(shù)列的推算規(guī)則,可以從第一個元素開始杀迹,推算出后續(xù)任意的元素,這種邏輯其實(shí)非常類似generator。
也就是說树酪,上面的函數(shù)和generator僅一步之遙浅碾。要把fib函數(shù)變成generator,只需要把print(b)改為yield b就可以了:

In [30]: def fib(times):
   ....:     n = 0
   ....:     a,b = 0,1
   ....:     while n<times:
   ....:         yield b
   ....:         a,b = b,a+b
   ....:         n+=1
   ....:     return 'done'
   ....: 

In [31]: F = fib(5)

In [32]: next(F)
Out[32]: 1

In [33]: next(F)
Out[33]: 1

In [34]: next(F)
Out[34]: 2

In [35]: next(F)
Out[35]: 3

In [36]: next(F)
Out[36]: 5

In [37]: next(F)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-37-8c2b02b4361a> in <module>()
----> 1 next(F)

StopIteration: done

在上面fib 的例子续语,我們在循環(huán)過程中不斷調(diào)用 yield 垂谢,就會不斷中斷。當(dāng)然要給循環(huán)設(shè)置一個條件來
退出循環(huán)疮茄,不然就會產(chǎn)生一個無限數(shù)列出來滥朱。同樣的,把函數(shù)改成generator后力试,我們基本上從來不會用
next() 來獲取下一個返回值徙邻,而是直接使用 for 循環(huán)來迭代:

In [38]: for n in fib(5):
   ....:     print(n)
   ....:     
1
1
2
3
5

In [39]:

但是用for循環(huán)調(diào)用generator時,發(fā)現(xiàn)拿不到generator的return語句的返回值畸裳。如果想要拿到返回值缰犁,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中:

In [39]: g = fib(5)

In [40]: while True:
   ....:     try:
   ....:         x = next(g)
   ....:         print("value:%d"%x)      
   ....:     except StopIteration as e:
   ....:         print("生成器返回值:%s"%e.value)
   ....:         break
   ....:     
value:1
value:1
value:2
value:3
value:5
生成器返回值:done

In [41]:
2-1.通過一個函數(shù)了解yield和send的意義怖糊。

例子:執(zhí)行到y(tǒng)ield時帅容,gen函數(shù)作用暫時保存,返回i的值;temp接收下次c.send("python")伍伤,send發(fā)送過來的值并徘,c.next()等價c.send(None)

>>> def gen():
...     i=0
...     while i<5:
...             temp = yield i
...             print(temp)
...             i+=1
...
 #  1. 使用next函數(shù)
>>> f=gen()
>>> next(f)
0
>>> next(f)
None
1
>>> next(f)
None
2
>>> next(f)
None
3
>>> next(f)
None
4
>>> next(f)
None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

#   2. 使用__next__()方法
>>> f=gen()
>>> f.__next__()
0
>>> f.__next__()
None
1
>>> f.__next__()
None
2
>>> f.__next__()
None
3
>>> f.__next__()
None
4
>>> f.__next__()
None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

#  3. 使用send方法:有下面例子可以看出,f.__next__()相當(dāng)于send(None)
>>> f=gen()
>>> f.__next__()
0
>>> f.send("haha")
haha
1
>>> f.__next__()
None
2
>>> f.send("heihei")
heihei
3
2-2.模擬多任務(wù)的實(shí)現(xiàn)

模擬多任務(wù)(進(jìn)程扰魂,線程麦乞,協(xié)程)實(shí)現(xiàn)方式之一:協(xié)程

>>> def test1():
...     while True:
...             print("__1__")
...             yield None
...
>>> def test2():
...     while True:
...             print("__2__")
...             yield None
...
>>> t1=test1()
>>> t2=test2()
>>> while True:
...     t1.__next__()
...     t2.__next__()

...# 打印結(jié)果:
__1__
__2__
__1__
__2__
__1__
__2__
__1__
__2__
__1__
__2__
......
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市阅爽,隨后出現(xiàn)的幾起案子路幸,更是在濱河造成了極大的恐慌,老刑警劉巖付翁,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件简肴,死亡現(xiàn)場離奇詭異,居然都是意外死亡百侧,警方通過查閱死者的電腦和手機(jī)砰识,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佣渴,“玉大人辫狼,你說我怎么就攤上這事⌒寥螅” “怎么了膨处?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我真椿,道長鹃答,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任突硝,我火速辦了婚禮测摔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘解恰。我一直安慰自己锋八,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布护盈。 她就那樣靜靜地躺著挟纱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪黄琼。 梳的紋絲不亂的頭發(fā)上樊销,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音脏款,去河邊找鬼围苫。 笑死,一個胖子當(dāng)著我的面吹牛撤师,可吹牛的內(nèi)容都是我干的剂府。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼剃盾,長吁一口氣:“原來是場噩夢啊……” “哼腺占!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起痒谴,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤衰伯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后积蔚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體意鲸,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年尽爆,在試婚紗的時候發(fā)現(xiàn)自己被綠了怎顾。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡漱贱,死狀恐怖槐雾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幅狮,我是刑警寧澤募强,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布株灸,位于F島的核電站,受9級特大地震影響钻注,放射性物質(zhì)發(fā)生泄漏蚂且。R本人自食惡果不足惜配猫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一幅恋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泵肄,春花似錦捆交、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至冯丙,卻和暖如春肉瓦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胃惜。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工泞莉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人船殉。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓鲫趁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親利虫。 傳聞我的和親對象是個殘疾皇子挨厚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • [TOC] 迭代器 為什么要用迭代器? 提供了一種不依賴索引的取值方式糠惫,使一些不具有索引屬性的對象也能遍歷輸出相比...
    派大星的喜悲沒人看見閱讀 591評論 0 0
  • 通過列表生成式疫剃,我們可以直接創(chuàng)建一個列表。但是硼讽,受到內(nèi)存限制巢价,列表容量肯定是有限的。而且理郑,創(chuàng)建一個包含100萬個元...
    喵在野閱讀 327評論 0 1
  • 1.什么是生成器 通過列表生成式蹄溉,我們可以直接創(chuàng)建一個列表。但是您炉,受到內(nèi)存限制柒爵,列表容量肯定是有限的。而且赚爵,創(chuàng)建一...
    一只寫程序的猿閱讀 937評論 0 4
  • 通過列表生成式棉胀,我們可以直接創(chuàng)建一個列表法瑟。但是,受到內(nèi)存限制唁奢,列表容量肯定是有限的霎挟。而且,創(chuàng)建一個包含100萬個元...
    chen_000閱讀 140評論 0 0
  • 姓名:張漢超 公司:東莞耀升機(jī)電有限公司 組別:4月25-27日六項精進(jìn)245期學(xué)員 【日精進(jìn)打卡第233天】 【...
    張漢超閱讀 92評論 0 0