在開(kāi)始課程之前,我要求學(xué)生們填寫一份調(diào)查表,這個(gè)調(diào)查表反映了它們對(duì)Python中一些概念的理解情況。一些話題("if/else控制流" 或者 "定義和使用函數(shù)")對(duì)于大多數(shù)學(xué)生是沒(méi)有問(wèn)題的。但是有一些話題,大多數(shù)學(xué)生只有很少,或者完全沒(méi)有任何接觸,尤其是“生成器和yield關(guān)鍵字”。我猜這對(duì)大多數(shù)新手Python程序員也是如此。
有事實(shí)表明,在我花了大功夫后,有些人仍然不能理解生成器和yield關(guān)鍵字。我想讓這個(gè)問(wèn)題有所改善。在這篇文章中,我將解釋yield關(guān)鍵字到底是什么,為什么它是有用的,以及如何來(lái)使用它。
注意:最近幾年,生成器的功能變得越來(lái)越強(qiáng)大,它已經(jīng)被加入到了PEP。在我的下一篇文章中,我會(huì)通過(guò)協(xié)程(coroutine),協(xié)同式多任務(wù)處理(cooperative multitasking),以及異步IO(asynchronous I/O)(尤其是GvR正在研究的 "tulip" 原型的實(shí)現(xiàn))來(lái)介紹yield的真正威力。但是在此之前,我們要對(duì)生成器和yield有一個(gè)扎實(shí)的理解.
協(xié)程與子例程
我們調(diào)用一個(gè)普通的Python函數(shù)時(shí),一般是從函數(shù)的第一行代碼開(kāi)始執(zhí)行,結(jié)束于return語(yǔ)句、異常或者函數(shù)結(jié)束(可以看作隱式的返回None)。一旦函數(shù)將控制權(quán)交還給調(diào)用者,就意味著全部結(jié)束。函數(shù)中做的所有工作以及保存在局部變量中的數(shù)據(jù)都將丟失。再次調(diào)用這個(gè)函數(shù)時(shí),一切都將從頭創(chuàng)建。
對(duì)于在計(jì)算機(jī)編程中所討論的函數(shù),這是很標(biāo)準(zhǔn)的流程。這樣的函數(shù)只能返回一個(gè)值,不過(guò),有時(shí)可以創(chuàng)建能產(chǎn)生一個(gè)序列的函數(shù)還是有幫助的。要做到這一點(diǎn),這種函數(shù)需要能夠“保存自己的工作”。
我說(shuō)過(guò),能夠“產(chǎn)生一個(gè)序列”是因?yàn)槲覀兊暮瘮?shù)并沒(méi)有像通常意義那樣返回。return隱含的意思是函數(shù)正將執(zhí)行代碼的控制權(quán)返回給函數(shù)被調(diào)用的地方。而"yield"的隱含意思是控制權(quán)的轉(zhuǎn)移是臨時(shí)和自愿的,我們的函數(shù)將來(lái)還會(huì)收回控制權(quán)。
在Python中,擁有這種能力的“函數(shù)”被稱為生成器,它非常的有用。生成器(以及yield語(yǔ)句)最初的引入是為了讓程序員可以更簡(jiǎn)單的編寫用來(lái)產(chǎn)生值的序列的代碼。 以前,要實(shí)現(xiàn)類似隨機(jī)數(shù)生成器的東西,需要實(shí)現(xiàn)一個(gè)類或者一個(gè)模塊,在生成數(shù)據(jù)的同時(shí)保持對(duì)每次調(diào)用之間狀態(tài)的跟蹤。引入生成器之后,這變得非常簡(jiǎn)單。
為了更好的理解生成器所解決的問(wèn)題,讓我們來(lái)看一個(gè)例子。在了解這個(gè)例子的過(guò)程中,請(qǐng)始終記住我們需要解決的問(wèn)題:生成值的序列。
注意:在Python之外,最簡(jiǎn)單的生成器應(yīng)該是被稱為協(xié)程(coroutines)的東西。在本文中,我將使用這個(gè)術(shù)語(yǔ)。請(qǐng)記住,在Python的概念中,這里提到的協(xié)程就是生成器。Python正式的術(shù)語(yǔ)是生成器;協(xié)程只是便于討論,在語(yǔ)言層面并沒(méi)有正式定義。
新聞熱點(diǎn)
疑難解答
圖片精選