Python關(guān)鍵字yield的用法詳解
Python里的一個(gè)非常重要但也頗具迷惑性的關(guān)鍵詞——yield。
什么是yield?為什么我們需要在Python中使用它?
來(lái),讓我們一起來(lái)拆解一下,看看yield到底是個(gè)啥。
迭代與可迭代對(duì)象
要搞明白yield,咱們先得弄清楚什么是可迭代對(duì)象(iterables)。
所謂可迭代對(duì)象,簡(jiǎn)單來(lái)說(shuō),就是你可以逐個(gè)讀取其元素的對(duì)象,比如列表、字符串、文件等等。舉個(gè)例子,當(dāng)你創(chuàng)建一個(gè)列表時(shí),你可以用for循環(huán)一個(gè)個(gè)地讀取它的元素:
mylist = [1, 2, 3]
for i in mylist:
print(i)輸出會(huì)是:
1
2
3
這里的mylist就是一個(gè)可迭代對(duì)象。你還可以用列表推導(dǎo)式(list comprehension)來(lái)創(chuàng)建一個(gè)列表,它同樣也是可迭代的:
mylist = [x*x for x in range(3)]
for i in mylist:
print(i)輸出是:???????
0
1
4
凡是你可以用for... in...來(lái)操作的東西,都是可迭代對(duì)象,包括列表、字符串、文件等等。
可迭代對(duì)象非常方便,因?yàn)槟憧梢匀我舛啻蔚刈x取它們的值,但前提是你得把所有值都存儲(chǔ)在內(nèi)存里。這就帶來(lái)了一個(gè)問(wèn)題:當(dāng)數(shù)據(jù)量很大時(shí),這種方式顯然不太合適。
生成器
生成器(generators)是迭代器的一種,你只能遍歷它們一次。生成器不像列表那樣把所有的值都存儲(chǔ)在內(nèi)存里,而是即用即生成。來(lái)看看生成器的例子:???????
mygenerator = (x*x for x in range(3))
for i in mygenerator:
print(i)輸出和列表推導(dǎo)式一樣:???????
0
1
4
但注意了,生成器只能使用一次,因?yàn)樗鼈儠?huì)“邊用邊忘”:計(jì)算0后忘記0,計(jì)算1后忘記1,最后計(jì)算4后結(jié)束。再用同一個(gè)生成器對(duì)象做for循環(huán)就沒(méi)有結(jié)果了。
yield關(guān)鍵詞
說(shuō)到y(tǒng)ield,這是個(gè)類(lèi)似于return的關(guān)鍵詞,但它返回的不是一個(gè)值,而是一個(gè)生成器??纯催@個(gè)例子:???????
def create_generator():
mylist = range(3)
for i in mylist:
yield i*i
mygenerator = create_generator() # 創(chuàng)建一個(gè)生成器
print(mygenerator) # mygenerator 是一個(gè)生成器對(duì)象!輸出是:
<generator object create_generator at 0xb7555c34>
通過(guò)for循環(huán)遍歷這個(gè)生成器:???????
for i in mygenerator:
print(i)輸出:???????
0
1
4
這個(gè)例子看起來(lái)簡(jiǎn)單,但它在處理大量數(shù)據(jù)時(shí)特別有用,因?yàn)樯善髦辉谛枰獣r(shí)生成值,而不是一次性生成所有值然后存儲(chǔ)在內(nèi)存中。
深入理解yield
為了徹底掌握yield,我們需要理解當(dāng)調(diào)用生成器函數(shù)時(shí),函數(shù)體內(nèi)的代碼并不會(huì)立即執(zhí)行。函數(shù)返回的是一個(gè)生成器對(duì)象,然后你的代碼會(huì)在每次調(diào)用for循環(huán)時(shí)從上次中斷的地方繼續(xù)執(zhí)行,直到遇到下一個(gè)yield。
第一次調(diào)用for循環(huán)時(shí),生成器對(duì)象會(huì)從頭開(kāi)始運(yùn)行函數(shù)中的代碼,直到遇到y(tǒng)ield,然后返回循環(huán)中的第一個(gè)值。隨后的每次調(diào)用都會(huì)執(zhí)行函數(shù)中循環(huán)的下一次迭代,直到生成器不再有值返回。這可能是因?yàn)檠h(huán)結(jié)束了,或者條件不再滿足。
來(lái)看看一個(gè)實(shí)際的例子:???????
def _get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild這里的代碼在每次使用生成器對(duì)象時(shí)都會(huì)被調(diào)用:
如果節(jié)點(diǎn)對(duì)象還有左子節(jié)點(diǎn)并且距離合適,返回下一個(gè)子節(jié)點(diǎn)。
如果節(jié)點(diǎn)對(duì)象還有右子節(jié)點(diǎn)并且距離合適,返回下一個(gè)子節(jié)點(diǎn)。
如果沒(méi)有更多子節(jié)點(diǎn),生成器會(huì)被認(rèn)為是空的。
調(diào)用這個(gè)生成器的方法如下:???????
result, candidates = list(), [self]
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result這里的代碼有幾個(gè)巧妙之處:
循環(huán)遍歷一個(gè)列表,而列表在循環(huán)過(guò)程中會(huì)擴(kuò)展。這樣可以方便地遍歷所有嵌套的數(shù)據(jù),雖然有些危險(xiǎn),因?yàn)榭赡軙?huì)陷入無(wú)限循環(huán)。在這個(gè)例子中,candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))用盡生成器的所有值,但while循環(huán)不斷創(chuàng)建新的生成器對(duì)象,因?yàn)樗鼈冏饔迷诓煌墓?jié)點(diǎn)上會(huì)產(chǎn)生不同的值。
extend()方法是列表對(duì)象的方法,它期望一個(gè)可迭代對(duì)象,并將其值添加到列表中。通常我們傳遞一個(gè)列表給它,但在代碼中,它接收一個(gè)生成器,這是個(gè)好主意,因?yàn)椋?/p>
你不需要讀取值兩次。
你可能有很多子節(jié)點(diǎn),不想全部存儲(chǔ)在內(nèi)存中。
這段代碼展示了Python為何如此酷:它不在乎方法的參數(shù)是列表還是其他可迭代對(duì)象。這種特性叫鴨子類(lèi)型(duck typing),也是Python靈活性的一個(gè)體現(xiàn)。
高級(jí)用法
再來(lái)看一個(gè)更高級(jí)的用法——控制生成器的耗盡:???????
class Bank():
crisis = False
def create_atm(self):
while not self.crisis:
yield "$100"
hsbc = Bank()
corner_street_atm = hsbc.create_atm()
print(next(corner_street_atm)) # 輸出 $100
print(next(corner_street_atm)) # 輸出 $100
print([next(corner_street_atm) for _ in range(5)]) # 輸出 ['$100', '$100', '$100', '$100', '$100']
hsbc.crisis = True
print(next(corner_street_atm)) # 輸出 StopIteration這里我們模擬了一個(gè)ATM機(jī),在銀行沒(méi)有危機(jī)時(shí),你可以不斷取錢(qián),但一旦危機(jī)來(lái)了,ATM機(jī)就會(huì)停止工作,即使是新的ATM機(jī)也不能再取錢(qián)了。
itertools模塊
最后,給大家介紹一個(gè)非常有用的模塊——itertools。這個(gè)模塊包含了很多操作可迭代對(duì)象的特殊函數(shù)。如果你曾經(jīng)希望復(fù)制一個(gè)生成器、連接兩個(gè)生成器、用一行代碼將值分組到嵌套列表中,或者在不創(chuàng)建另一個(gè)列表的情況下使用map和zip,那么就應(yīng)該導(dǎo)入itertools。
舉個(gè)例子,我們看看四匹馬比賽的可能到達(dá)順序:???????
import itertools horses = [1, 2, 3, 4] races = itertools.permutations(horses) print(list(itertools.permutations(horses)))
輸出:
[(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2), (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1), (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1), (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)]
itertools模塊簡(jiǎn)直是Python程序員的好伙伴,可以讓你在處理迭代對(duì)象時(shí)如虎添翼。
總結(jié)
yield是Python中一個(gè)強(qiáng)大的工具,它可以幫助你以一種高效的方式處理大量數(shù)據(jù)。理解yield的工作原理對(duì)于掌握Python編程至關(guān)重要。
在大數(shù)據(jù)時(shí)代,處理海量數(shù)據(jù)已成為常態(tài)。生成器作為一種高效的數(shù)據(jù)處理方式,因其優(yōu)越的內(nèi)存管理能力,受到了越來(lái)越多開(kāi)發(fā)者的青睞。無(wú)論是日志處理、數(shù)據(jù)流分析,還是實(shí)時(shí)數(shù)據(jù)處理,生成器都展現(xiàn)了不可替代的價(jià)值。
通過(guò)對(duì)yield的詳解,我們不僅理解了它的基本概念和用法,還認(rèn)識(shí)到它在高效數(shù)據(jù)處理中的重要性。掌握yield,將為你的Python編程之旅增添一把利器。
以上就是Python關(guān)鍵字yield的用法詳解的詳細(xì)內(nèi)容,更多關(guān)于Python關(guān)鍵字yield的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在pytorch中動(dòng)態(tài)調(diào)整優(yōu)化器的學(xué)習(xí)率方式
這篇文章主要介紹了在pytorch中動(dòng)態(tài)調(diào)整優(yōu)化器的學(xué)習(xí)率方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06
使用Python做垃圾分類(lèi)的原理及實(shí)例代碼附源碼
這篇文章主要介紹了用Python做垃圾分類(lèi)的實(shí)現(xiàn)原理,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-07-07
在DigitalOcean的服務(wù)器上部署flaskblog應(yīng)用
這篇文章主要介紹了在DigitalOcean的服務(wù)器上部署flaskblog的方法,flaskblog是用Python的Flask開(kāi)發(fā)的一個(gè)博客程序,而DigitalOcean則是大受歡迎的SSD主機(jī)提供商,需要的朋友可以參考下2015-12-12
Python進(jìn)階學(xué)習(xí)之帶你探尋Python類(lèi)的鼻祖-元類(lèi)
這篇文章主要介紹了Python進(jìn)階學(xué)習(xí)之帶你探尋Python類(lèi)的鼻祖-元類(lèi),文中有非常詳細(xì)的解釋,對(duì)正在學(xué)習(xí)python的小伙伴們有很好的幫助,需要的朋友可以參考下2021-05-05
tkinter動(dòng)態(tài)顯示時(shí)間的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了tkinter動(dòng)態(tài)顯示時(shí)間的兩種實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
Python 中 and, or, &, |, ^ 
這篇文章主要介紹了Python 中 and, or, &, |, ^ 的使用小結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01

