Python關(guān)鍵字yield的使用場景及用法詳解
一、yield 的基本概念
在 Python 編程語言中,yield是一個至關(guān)重要的關(guān)鍵字,它用于定義生成器函數(shù)(generator function)。與普通函數(shù)使用return返回結(jié)果不同,生成器函數(shù)使用yield產(chǎn)生一個值,同時"凍結(jié)"函數(shù)的當(dāng)前狀態(tài),使得下次調(diào)用時可以從凍結(jié)點繼續(xù)執(zhí)行。
yield的出現(xiàn)使得 Python 能夠優(yōu)雅地實現(xiàn)惰性計算(lazy evaluation),這種特性在處理大數(shù)據(jù)集或無限序列時尤為有用。傳統(tǒng)函數(shù)在返回結(jié)果后會釋放所有資源并忘記之前的執(zhí)行狀態(tài),而生成器函數(shù)則能夠記住它的狀態(tài),在需要時繼續(xù)產(chǎn)生下一個值。
二、生成器函數(shù)與普通函數(shù)的區(qū)別
生成器函數(shù)與普通函數(shù)在定義上非常相似,唯一的區(qū)別在于前者使用yield而非return。但這種表面上的微小差異帶來了行為上的巨大不同:
- 執(zhí)行流程:普通函數(shù)從開始執(zhí)行到 return 語句后立即退出,而生成器函數(shù)在遇到 yield 時會暫停執(zhí)行,保存所有局部變量狀態(tài),等待下一次調(diào)用。
- 內(nèi)存使用:普通函數(shù)需要一次性計算所有結(jié)果并存儲在內(nèi)存中,生成器則是按需生成值,大大節(jié)省內(nèi)存空間。
- 返回值:普通函數(shù)返回一個具體的值或?qū)ο螅善骱瘮?shù)返回一個生成器對象,這個對象遵循迭代器協(xié)議。
例如,比較以下兩個函數(shù):
# 普通函數(shù)
def squares(n):
result = []
for i in range(n):
result.append(i*i)
return result
# 生成器函數(shù)
def squares_gen(n):
for i in range(n):
yield i*i
第一個函數(shù)會一次性生成所有平方數(shù)并存儲在列表中,而第二個函數(shù)則會在每次迭代時生成一個平方數(shù),內(nèi)存效率更高。
三、yield 的工作機制
理解yield的工作機制對于掌握生成器至關(guān)重要。當(dāng) Python 解釋器遇到包含yield語句的函數(shù)時,它會將其特殊處理為一個生成器函數(shù)。調(diào)用生成器函數(shù)時,不會立即執(zhí)行函數(shù)體,而是返回一個生成器對象。
生成器對象實現(xiàn)了迭代器協(xié)議,即包含__iter__()和__next__()方法。每次調(diào)用next()函數(shù)或在 for 循環(huán)中迭代時,生成器函數(shù)會從上次暫停的位置繼續(xù)執(zhí)行,直到遇到下一個yield語句,此時yield后的表達(dá)式值會被返回給調(diào)用者,函數(shù)狀態(tài)再次被凍結(jié)。
當(dāng)函數(shù)執(zhí)行完畢(或遇到 return 語句)時,生成器會拋出StopIteration異常,表示迭代結(jié)束。這個異常通常被 for 循環(huán)等迭代上下文自動處理。
四、yield 的常見使用場景
- 處理大型數(shù)據(jù)集:當(dāng)需要處理的數(shù)據(jù)量太大而無法一次性裝入內(nèi)存時,生成器可以逐項產(chǎn)生數(shù)據(jù),顯著降低內(nèi)存消耗。
def read_large_file(file_path):
with open(file_path, 'r') as f:
for line in f:
yield line.strip()
- 生成無限序列:生成器可以表示無限序列,如斐波那契數(shù)列、素數(shù)序列等,因為值是按需生成的。
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
- 實現(xiàn)管道:多個生成器可以串聯(lián)起來形成處理管道,每個生成器負(fù)責(zé)特定的處理步驟。
def filter_even(numbers):
for n in numbers:
if n % 2 == 0:
yield n
def square(numbers):
for n in numbers:
yield n ** 2
# 使用管道
numbers = range(100)
result = square(filter_even(numbers))
- 協(xié)程和狀態(tài)保持:生成器可以用于實現(xiàn)簡單的協(xié)程,保持函數(shù)狀態(tài)并在不同時間點進(jìn)行交互。
五、yield 的高級用法
除了基本用法外,yield還有一些更高級的應(yīng)用:
- yield from:Python 3.3 引入的
yield from語法用于委托生成器,簡化了生成器的嵌套使用。
def chain(*iterables):
for it in iterables:
yield from it
- 生成器表達(dá)式:類似于列表推導(dǎo)式,但使用圓括號,返回一個生成器對象。
gen = (x*x for x in range(10)) # 生成器表達(dá)式
- 雙向通信:生成器可以通過
send()方法接收數(shù)據(jù),實現(xiàn)雙向通信。
def accumulator():
total = 0
while True:
value = yield total
if value is None:
break
total += value
六、性能考量
使用生成器可以帶來顯著的性能優(yōu)勢,特別是在內(nèi)存使用方面。由于生成器是惰性求值的,它們:
- 減少內(nèi)存占用,不需要預(yù)先存儲所有結(jié)果
- 可以立即開始產(chǎn)生第一個值,而不必等待所有計算完成
- 適用于流式數(shù)據(jù)處理和實時系統(tǒng)
然而,生成器也有一些限制:
- 生成器只能迭代一次,要重復(fù)使用需要重新創(chuàng)建生成器
- 無法隨機訪問,只能順序訪問
- 在某些情況下,如果所有數(shù)據(jù)確實需要同時存在,使用列表可能更直接
以上就是Python中關(guān)鍵字yield的使用場景及用法詳解的詳細(xì)內(nèi)容,更多關(guān)于Python關(guān)鍵字yield的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用OpenCV對運動員的姿勢進(jìn)行檢測功能實現(xiàn)
2022年奧林匹克運動會如期舉行,以不正確的方式進(jìn)行運動風(fēng)險在增加,人體姿勢估計是計算機視覺領(lǐng)域的重要問題,接下來通過本文給大家介紹下使用OpenCV對運動員的姿勢進(jìn)行檢測功能,感興趣的朋友一起看看吧2022-02-02
點云地面點濾波(Cloth Simulation Filter, CSF)
這篇文章主要介紹了點云地面點濾波(Cloth Simulation Filter, CSF)“布料”濾波算法介紹,本文從基本思想到實現(xiàn)思路一步步給大家講解的非常詳細(xì),需要的朋友可以參考下2021-08-08
DjangoUeditor圖片不顯示img的src沒有域名問題
在使用DjangoUeditor過程中,可能遇到圖片上傳后不顯示問題,解決辦法是修改源碼view.py,加入代碼使得保存的圖片URL帶有協(xié)議和域名,具體做法是在保存圖片代碼中添加request.scheme獲取協(xié)議,request.META['HTTP_HOST']獲取域名2024-09-09
Python腳本實現(xiàn)DNSPod DNS動態(tài)解析域名
這篇文章主要介紹了Python腳本實現(xiàn)DNSPod DNS動態(tài)解析域名,本文直接給出實現(xiàn)代碼,需要的朋友可以參考下2015-02-02

