Python?迭代器和生成器概念及場景分析
迭代器的介紹
迭代器的定義:迭代器(Iterator)是 Python 中用于遍歷數(shù)據(jù)集合的核心機(jī)制。它提供了一種統(tǒng)一的方式來訪問容器(如列表、字典、文件等)中的元素,而無需關(guān)心底層數(shù)據(jù)結(jié)構(gòu)的具體實現(xiàn)。迭代器的核心特點是按需生成數(shù)據(jù),避免一次性加載所有數(shù)據(jù)到內(nèi)存。
迭代器適合處理大型數(shù)據(jù)、無限序列或需要惰性計算的場景。
迭代器的核心概念:
迭代器協(xié)議:
- 一個對象要成為迭代器,必須實現(xiàn)以下兩個方法:
__iter__()
:返回迭代器對象本身(通常直接return self
)。__next__()
:返回下一個元素,若沒有更多元素則拋出StopIteration
異常。
- Python 的
for
循環(huán)、next()
函數(shù)等底層都依賴這一協(xié)議。
- 一個對象要成為迭代器,必須實現(xiàn)以下兩個方法:
可迭代對象(Iterable) VS 迭代器(Iterator):
差異體現(xiàn)在遍歷機(jī)制:
- 可迭代對象:實現(xiàn)了
__iter__()
方法,可以返回一個迭代器的對象(如列表、元組、字典)。 - 迭代器:實現(xiàn)了
__iter__()
和__next__()
方法的對象。 - 所有迭代器都是可迭代對象,但可迭代對象本身不一定是迭代器。
- 可迭代對象:實現(xiàn)了
可迭代對象:
每次調(diào)用 iter()
會生成新的迭代器,因此可被多次遍歷:
my_list = [1, 2, 3] for x in my_list: print(x) # 輸出 1,2,3 for x in my_list: print(x) # 再次輸出 1,2,3
迭代器:
遍歷是一次性的,遍歷完成后無法重置:
iterator = iter(my_list) for x in iterator: print(x) # 輸出 1,2,3 for x in iterator: print(x) # 無輸出(迭代器已耗盡)
自定義迭代器
示例 1: 通過類實現(xiàn)迭代器
class CountUpTo: def __init__(self, max_num): self.max_num = max_num self.current = 0 def __iter__(self): return self # 返回迭代器本身 def __next__(self): if self.current < self.max_num: self.current += 1 return self.current else: raise StopIteration # 終止迭代 # 使用自定義迭代器 counter = CountUpTo(3) for num in counter: print(num) # 輸出 1, 2, 3
示例 2: 通過生成器函數(shù)實現(xiàn)(簡化版)
生成器函數(shù)(使用 yield
)是創(chuàng)建迭代器的快捷方式:
def count_up_to(max_num): current = 0 while current < max_num: current += 1 yield current # 生成器返回的也是迭代器 for num in count_up_to(3): print(num) # 輸出 1, 2, 3
省略的迭代器
寫過for循環(huán)的都知道,我沒用迭代器呀!
用了!只不過是編譯器幫你用了。
以下兩段代碼完全等價:
# 直接遍歷列表 my_list = [1, 2, 3, 4, 5] for x in my_list: print(x)
# 等價的手動迭代器操作 iterator = iter(my_list) # 自動調(diào)用 __iter__() 獲取迭代器 while True: try: x = next(iterator) # 自動調(diào)用 __next__() print(x) except StopIteration: break # 自動處理終止
為什么不需要顯式寫迭代器?
語法糖(Syntactic Sugar):for 循環(huán)是 Python 提供的一種簡化語法,隱藏了迭代器的創(chuàng)建和異常處理細(xì)節(jié)。
統(tǒng)一接口:所有可迭代對象(如列表、元組、字典、集合、字符串等)都可以通過 for 循環(huán)統(tǒng)一處理,無需關(guān)心底層是列表還是其他數(shù)據(jù)結(jié)構(gòu)。
生產(chǎn)器的介紹
yield是個英文動詞,也是名詞,含義是生產(chǎn)的意思。
yield 在 Python里就是生成器。
yield的定義:Python 的 yield 關(guān)鍵字用于定義生成器函數(shù)(Generator Function),生成器是一種特殊的迭代器,能夠按需生成值并暫停/恢復(fù)執(zhí)行狀態(tài)。它的核心特性是惰性求值(Lazy Evaluation),適用于處理大數(shù)據(jù)流、無限序列或需要節(jié)省內(nèi)存的場景。
核心概念:
生成器函數(shù):
- 使用
yield
代替return
的函數(shù)。 - 調(diào)用生成器函數(shù)時,返回一個生成器對象(迭代器),而非直接執(zhí)行函數(shù)體。
- 生成器通過
next()
或for
循環(huán)逐步執(zhí)行,每次遇到yield
時暫停,返回yield
后的值,并在下次調(diào)用時從暫停處繼續(xù)執(zhí)行。
- 使用
與普通函數(shù)的區(qū)別:
- 普通函數(shù)一次執(zhí)行完畢,返回一個結(jié)果。
- 生成器函數(shù)逐步產(chǎn)生多個值,并在
yield
處保持狀態(tài)。
與 return 的區(qū)別:
特性 | yield | return |
---|---|---|
返回值數(shù)量 | 可多次返回值 | 僅返回一次 |
函數(shù)狀態(tài) | 暫停并保留狀態(tài) | 終止函數(shù)執(zhí)行 |
返回類型 | 生成器對象(迭代器) | 直接返回值 |
內(nèi)存占用 | 低(按需生成) | 高(一次性生成所有數(shù)據(jù)) |
yield的普通用法
示例 1: 簡單生成器
def simple_generator(): yield 1 yield 2 yield 3 gen = simple_generator() print(next(gen)) # 輸出 1 print(next(gen)) # 輸出 2 print(next(gen)) # 輸出 3 # 繼續(xù)調(diào)用 next(gen) 會拋出 StopIteration 異常
示例 2: 用 for
循環(huán)遍歷生成器
def count_up_to(n): i = 0 while i < n: yield i i += 1 for num in count_up_to(5): print(num) # 輸出 0, 1, 2, 3, 4
yield的高級用法
通過 send()
傳遞值生成器可以通過 send(value)
接收外部傳入的值,賦值給 yield
表達(dá)式:
def generator_with_send(): value = yield "Ready to receive" yield f"Received: {value}" gen = generator_with_send() print(next(gen)) # 輸出 "Ready to receive" print(gen.send("Hello")) # 輸出 "Received: Hello"
yield from
委托生成Python 3.3+ 引入 yield from
,用于簡化嵌套生成器的操作:
def sub_generator(): yield "A" yield "B" def main_generator(): yield from sub_generator() yield "C" for item in main_generator(): print(item) # 輸出 A, B, C
異常處理生成器可以通過 throw()
方法接收異常:
def generator_with_exception(value): try: yield 10 / value except ZeroDivisionError as e: yield "Caught ValueError" gen = generator_with_exception(2) print(next(gen)) gen = generator_with_exception(0) print(next(gen))
out:
5.0
Caught ValueError
yidle的實際應(yīng)用案例
大數(shù)據(jù)處理:
def read_large_file(file_path): with open(file_path, "r") as file: for line in file: yield line.strip() # 逐行生成,避免一次性加載到內(nèi)存 for line in read_large_file("data.txt"): process(line)
生成無限序列:
def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b fib = fibonacci() print([next(fib) for _ in range(10)]) # 前10個斐波那契數(shù)
協(xié)程(Coroutine):
def coroutine(): while True: task = yield print(f"Processing: {task}") worker = coroutine() next(worker) # 啟動協(xié)程 worker.send("Task1") # 輸出 "Processing: Task1" worker.send("Task2") # 輸出 "Processing: Task2"
在 Python 中,協(xié)程(Coroutine) 是一種可以暫停和恢復(fù)執(zhí)行的函數(shù),它能與調(diào)用方進(jìn)行雙向通信(接收和發(fā)送數(shù)據(jù)),常用于實現(xiàn)協(xié)作式多任務(wù)(非搶占式任務(wù)切換)。
上文提供的代碼是一個典型的基于生成器的協(xié)程(Generator-based Coroutine)。
總結(jié)
yield
是 Python 中實現(xiàn)惰性計算和協(xié)程的核心工具,結(jié)合 send()
、throw()
、close()
等方法,能夠構(gòu)建高效、靈活的數(shù)據(jù)流和控制流模型。
到此這篇關(guān)于Python 迭代器和生成器概念的文章就介紹到這了,更多相關(guān)Python 迭代器和生成器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python調(diào)用GPT3.5接口的最新方法實例詳解
這篇文章主要介紹了Python調(diào)用GPT3.5接口的最新方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03python爬蟲爬取股票的北上資金持倉數(shù)據(jù)
這篇文章主要介紹了python爬蟲爬取股票的北上資金持倉數(shù)據(jù),文章基于python的相關(guān)資料展開爬取數(shù)據(jù)的詳細(xì)內(nèi)容,具有一定的參考價值,需要的小伙伴可以參考一下2022-05-05Python學(xué)習(xí)筆記之json模塊和pickle模塊
json和pickle模塊是將數(shù)據(jù)進(jìn)行序列化處理,并進(jìn)行網(wǎng)絡(luò)傳輸或存入硬盤,下面這篇文章主要給大家介紹了關(guān)于Python學(xué)習(xí)筆記之json模塊和pickle模塊的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05Python數(shù)據(jù)分析入門之教你怎么搭建環(huán)境
本篇文章要有一定的Python基礎(chǔ),知道列表,字符串,函數(shù)等的用法. 文中有非常詳細(xì)的代碼示例,對正在入門python數(shù)據(jù)分析的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05