久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

關(guān)于生成器的那些事兒

 LibraryPKU 2017-11-29
作者:李者璈


寫在前面的話
?

本來想這周繼續(xù)寫寫 Flask 那點(diǎn)破事兒的,但是想了想決定換換口味,,來聊聊很不容易理解但是很重要的 Python中的生成器和協(xié)程,。

?
Generators 科普


       我猜大家對于生成器肯定并不陌生,但是為了能讓我愉快的繼續(xù)裝逼,,我們還是用點(diǎn)篇幅講一下什么是生成器吧,。比如在 Python 里,我們想生成一個(gè)范圍 (1,100000) 的一個(gè) list,,于是我們無腦寫了如下的代碼出來


注1:這里有同學(xué)提出了為什么我們不直接返回 range(start,stop) ,,Nice question,這里涉及到一個(gè)基礎(chǔ)問題,, range 的機(jī)制究竟是怎樣的,。這就要分版本而論了,在 Python 2.x 的版本中,, range(start,stop)其實(shí)本質(zhì)上是預(yù)先生成一個(gè) list ,而 list 對象是一個(gè) Iterator ,,因此可以被 for 語句所使用。

然后在 Python 2.x 中還有一個(gè)語句叫做 xrange ,,其生成的是一個(gè) Generator 對象,。


在 Python 3 中事情發(fā)生了一點(diǎn)變化,可能社區(qū)覺得 range 和 xrange 分裂太過蛋疼,,于是將其合并,,于是現(xiàn)在在 Python 3 中,,取消了 xrange 的語法糖,然后 range 的機(jī)制也變成生成一個(gè) Generator 而不是list


但是大家考慮過一個(gè)問題么,,如果我們想生成數(shù)據(jù)量非常大,,預(yù)先生成數(shù)據(jù)的行為無疑是很不明智的,,這樣會耗費(fèi)大量的內(nèi)存,。于是 Python 給我們提供了一種新的姿勢,Generator (生成器),。


是的,,Generator 其中一個(gè)特性就是不是一次性生成數(shù)據(jù),而是生成一個(gè)可迭代的對象,,在迭代時(shí),,根據(jù)我們所寫的邏輯來控制其啟動時(shí)機(jī)。


Generator 深入


這里可能有一個(gè)問題,,大家肯定想問 Python 開發(fā)者們不可能為了這一種使用場景而去單獨(dú)創(chuàng)建一個(gè) Generator 機(jī)制吧,,那么我們 Generator 還有其余的使用場景么。當(dāng)然,,請看標(biāo)題,,對了嘛,Generator 另一個(gè)很大作用可以說就是當(dāng)做協(xié)程使用,。不過在這之前,,我們要去深入的了解下 Generator 才能方便我們后面的講解。


 Generator 內(nèi)建方法


關(guān)于 Python 中可迭代對象的一點(diǎn)背景知識

首先,,我們來看看 Python 中的迭代過程,。
在 Python 中迭代有兩個(gè)概念,一個(gè)是 Iterable ,,另一個(gè)是 Iterator ,。讓我們分別來看看。
第N次首先,,Iterable 近似的可以理解成為一個(gè)協(xié)議,,判斷一個(gè) Object 是否是 Iterable 的方法就是看其實(shí)現(xiàn)了 iter與否,如果實(shí)現(xiàn)了 iter ,,那么這便可以認(rèn)為是一個(gè) Iterable 對象,。空談?wù)`國,,實(shí)干興邦,,讓我們直接來看一段代碼理解下:


好了,讓我們來看看上面這段代碼里發(fā)生了什么,,首先 for 語句的引用首先去判斷迭代的是 Iterable 對象還是Iterator 對象,,如果是實(shí)現(xiàn)了 __iter__ 方法的對象,,那么就是一個(gè) Iterable 對象, for 循環(huán)首先調(diào)用對象的__iter__ 方法來獲取一個(gè) Iterator 對象,。那么什么是 Iterator 對象呢,,這里可以近似的理解為是實(shí)現(xiàn)了 next() 方法(注:在Python3中是 next 方法)。


OK,,讓我們繼續(xù)回到剛剛說到的那里,,在上面的代碼中 for 語句首先判斷是一個(gè) Iterable 對象還是 Iterator 對象,如果是 Iterable 對象那么調(diào)用其 iter 方法來獲取一個(gè) Iterator 對象,,接著 for 循環(huán)會調(diào)用 Iterator 對象中的next() (注:Python3 里是 __next__ )方法來進(jìn)行迭代,,直到迭代過程結(jié)束拋出 StopIteration 異常。


聊聊 Generator 吧


讓我們先看看前面那段代碼吧:


首先我們要確定一點(diǎn)的是 Generator 其實(shí)也是一個(gè) Iterator 對象,。OK 讓我們來看看上面這段代碼,,首先 for 確定 generateList1 是一個(gè) Iterator 對象,然后開始調(diào)用 next() 方法進(jìn)行進(jìn)一步迭代,。OK 此時(shí)你肯定想問這里面 next() 方法是怎樣讓 generateList1 進(jìn)一步往下迭代的呢,?答案在于 Generator 的內(nèi)建 send() 方法。我們還是來看一段代碼,。


這里我們應(yīng)該輸出什么,?答案就是 0,1,2,3,4 ,結(jié)果上和我們用 for 循環(huán)進(jìn)行運(yùn)算的結(jié)果是不是一樣,。好了,,我們現(xiàn)在可以得出一個(gè)結(jié)論就是:

Generator 迭代的本質(zhì)就是通過內(nèi)建的 next() 或 __next__() 方法來調(diào)用內(nèi)建的 send() 方法。


繼續(xù)吐槽內(nèi)建方法


前面我們提到一個(gè)結(jié)論 :

Generator 迭代的本質(zhì)就是通過內(nèi)建的 next() 或 __next__() 方法來調(diào)用內(nèi)建的 send() 方法,。

現(xiàn)在我們來看個(gè)例子:


好了這段代碼的輸出應(yīng)該是什么,?
答案是 [5,2,,1,,0] ,是不是很迷惑,?別急,,我們先來看看這段代碼的運(yùn)行流程


簡而言之就是,當(dāng)我們調(diào)用 send() 函數(shù)的時(shí)候,,我們 send(x) 的值會發(fā)送給 newvalue 向下繼續(xù)執(zhí)行直到遇到下一次 yield 的出現(xiàn),,然后返回值作為一個(gè)過程的結(jié)束。然后我們的 Generator 靜靜的沉睡在內(nèi)存中,,等待下一
次的 send 來喚醒它,。


注2:有同志問:“這里沒想明白,c.send(3) 是 相當(dāng)于 yield n 返回了個(gè) 3 給 newvalue ?”,,好的,,nice question,,其實(shí)這個(gè)問題我們看前面之前的代碼運(yùn)行圖就知道, c.send(3) 首先,,將 3 賦值給 newvalue,,然后程序運(yùn)行剩下的代碼,,直到遇到下一個(gè) yield 為止,那么在這里,,我們運(yùn)行剩下完代碼,,在遇到y(tǒng)iled n 之前,將 n 的值已經(jīng)改變?yōu)?3 ,接著,, yield n 即約等于 return 3 。接著 countdown 這個(gè)Generator 將所有變量的狀態(tài)凍結(jié),,然后靜靜的呆在內(nèi)存中,,等待下一次的 next 或 __next__() 方法或者
是 send() 方法的喚醒。


小貼士:我們?nèi)绻苯诱{(diào)用 send() 的話,,第一次請務(wù)必 send(None) 只有這樣一個(gè) Generator 才算是真正被激活了,。我們才能進(jìn)行下一步操作。


說說關(guān)于協(xié)程


首先關(guān)于協(xié)程的定義,,我們來看一段 wiki


Coroutines are computer program components that generalize subroutines for nonpreemptive multitasking,by allowing multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing more familiar program components such as cooperative tasks, exceptions,event loop, iterators, infinite lists and pipes.
According to Donald Knuth, the term coroutine was coined by Melvin Conway in 1958, after he applied it to construction of an assembly program.[1] The first published explanation of the coroutine appeared later, in 1963.


簡而言之,,協(xié)程是比線程更為輕量的一種模型,我們可以自行控制啟動與停止的時(shí)機(jī),。在 Python 中其實(shí)沒有專門針對協(xié)程的這個(gè)概念,,社區(qū)一般而言直接將 Generator 作為一種特殊的協(xié)程看待,想想,,我們可以用 next 或__next__() 方法或者是 send() 方法喚醒我們的 Generator ,,在運(yùn)行完我們所規(guī)定的代碼后, Generator 返回并將其所有狀態(tài)凍結(jié),。這是不是很讓我們 Excited 呢?。?/span>


課后作業(yè)


現(xiàn)在我們要后序遍歷二叉樹,,我知道看這篇文章神犇們都能無腦寫出來的,,讓我們看看代碼先:


但是,我們知道遞歸深度太深的話,,我們要么爆棧要么 py 交易失敗,,OK ,Generator 大法好,,把你碼農(nóng)平安保,。

還是直接看代碼:


看起來很復(fù)雜是不是,?沒事當(dāng)做課后作業(yè),,大家可以在評論里給我留言,我們一起進(jìn)行一下 py 交易吧~


參考資料


1,、提高你的Python: 解釋‘yield’和‘Generators(生成器)’
2、yield大法好
3,、http://my.oschina.net/1123581321/blog/160560
4,、python的迭代器為什么一定要實(shí)現(xiàn)iter方法(關(guān)于迭代器那離,為了便于理解,,我簡化了一些東西,,具體可以參看這個(gè)問題的高票答案)

專欄作者簡介

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多