Python中迭代器和生成器讓數(shù)據(jù)“懶”得剛剛好
“聰明的程序員不是算得更快,而是算得更少。”
—— 迭代器與生成器,正是 Python 踐行這一哲學(xué)的優(yōu)雅體現(xiàn)。
問題引入
你有沒有遇到過這樣的場景?
- 想遍歷一個超大文件,但內(nèi)存爆了 ?
- 寫了個
range(10**9),結(jié)果電腦卡死 ?? - 面試被問:“迭代器和生成器有啥區(qū)別?” 瞬間語塞 ??
別慌!今天我們就把這兩個看似高冷的概念,用一杯咖啡的時間講清楚 ??。它們不是魔法,而是延遲計算(Lazy Evaluation) 的實用工具——只在你需要時才干活,絕不提前內(nèi)卷!
核心剖析
迭代器(Iterator):會“一步一步走”的對象
在 Python 中,迭代器是一個實現(xiàn)了 __iter__() 和 __next__() 方法的對象。它遵循迭代協(xié)議:
__iter__()返回自身(支持for循環(huán))__next__()返回下一個值,若無則拋出StopIteration
class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
return self
def __next__(self):
if self.start <= 0:
raise StopIteration
self.start -= 1
return self.start + 1
# 使用
for num in Countdown(3):
print(num) # 輸出: 3, 2, 1?? 所有可迭代對象(如 list、dict)本身不是迭代器,但可以通過
iter()轉(zhuǎn)成迭代器。
生成器(Generator):寫起來像函數(shù),用起來像迭代器
生成器是創(chuàng)建迭代器的“快捷方式”。你只需在函數(shù)中用 yield 替代 return,Python 自動幫你實現(xiàn)迭代協(xié)議!
def countdown_gen(n):
while n > 0:
yield n
n -= 1
# 使用
for num in countdown_gen(3):
print(num) # 輸出: 3, 2, 1關(guān)鍵區(qū)別來了??:
| 特性 | 迭代器 | 生成器 |
|---|---|---|
| 創(chuàng)建方式 | 手寫類 + __iter__/__next__ | 函數(shù) + yield |
| 內(nèi)存占用 | 手動控制 | 自動優(yōu)化,極低 |
| 可讀性 | 較繁瑣 | 極簡清晰 ? |
| 適用場景 | 復(fù)雜狀態(tài)管理 | 流式數(shù)據(jù)、無限序列 |
?? 生成器本質(zhì)是語法糖,但它甜得恰到好處!
動手實踐:處理大文件不崩內(nèi)存
假設(shè)你有一個 10GB 的日志文件,想逐行讀取并過濾錯誤信息:
def read_large_file(file_path):
"""生成器:按需讀取,不加載全文件到內(nèi)存"""
with open(file_path, 'r') as f:
for line in f:
if 'ERROR' in line:
yield line.strip()
# 使用(即使文件巨大,內(nèi)存也穩(wěn)如老狗)
for error_line in read_large_file('app.log'):
print(error_line)對比暴力做法 lines = open('app.log').readlines() —— 后者可能直接 OOM(Out of Memory)!
避坑指南 ??
生成器只能遍歷一次!
gen = (x for x in range(3)) list(gen) # [0, 1, 2] list(gen) # [] ← 已耗盡!
解決方案:需要多次使用?轉(zhuǎn)成 list,或重新調(diào)用生成器函數(shù)。
別混淆“可迭代對象”和“迭代器”
lst = [1, 2, 3] iter(lst) is iter(lst) # False!每次返回新迭代器 it = iter(lst) iter(it) is it # True!迭代器的 __iter__ 返回自己
生成器表達(dá)式 vs 列表推導(dǎo)式
# 列表推導(dǎo)式:立即計算,占內(nèi)存 squares_list = [x**2 for x in range(1000000)] # 生成器表達(dá)式:延遲計算,省內(nèi)存 squares_gen = (x**2 for x in range(1000000))
延伸思考
yield from 是什么?
它用于“委托”另一個生成器,避免嵌套 for 循環(huán)。比如合并多個生成器流。
生成器能接收外部數(shù)據(jù)嗎?
可以!通過 generator.send(value) 實現(xiàn)雙向通信,常用于協(xié)程(async/await 的底層基礎(chǔ)之一)。
為什么 range() 不是生成器?
因為它是可重復(fù)迭代的序列對象,且支持 len()、索引等操作——生成器做不到這些。
小結(jié) & 行動號召 ??
- 迭代器:協(xié)議驅(qū)動,手動實現(xiàn),靈活但啰嗦
- 生成器:
yield一行搞定,內(nèi)存友好,開發(fā)首選
下次當(dāng)你需要處理“大量數(shù)據(jù)”“無限序列”或“流式輸入”時,記得問自己:
“我能用生成器讓它‘懶’一點嗎?”
試試改寫你項目中的某個循環(huán),用生成器替代列表推導(dǎo)式,觀察內(nèi)存變化吧
到此這篇關(guān)于Python中迭代器和生成器讓數(shù)據(jù)“懶”得剛剛好 的文章就介紹到這了,更多相關(guān)Python迭代器和生成器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python隨機(jī)數(shù)用法實例詳解【基于random模塊】
這篇文章主要介紹了Python隨機(jī)數(shù)用法,結(jié)合實例形式分析了基于random模塊的各種隨機(jī)數(shù)操作常用技巧,需要的朋友可以參考下2017-04-04
關(guān)于WARNING:Ignoring?invalid?distribution?-pencv-python....
這篇文章主要給大家介紹了關(guān)于WARNING:Ignoring?invalid?distribution?-pencv-python....警告信息的處理方法,文中通過圖文將解決的辦法介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用python具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2023-03-03
Pandas技巧分享之創(chuàng)建測試數(shù)據(jù)
學(xué)習(xí)pandas的過程中,為了嘗試pandas提供的各類功能強大的函數(shù),常常需要花費很多時間去創(chuàng)造測試數(shù)據(jù),本篇介紹了一些快速創(chuàng)建測試數(shù)據(jù)的方法,需要的可以參考一下2023-07-07
Pytorch深度學(xué)習(xí)經(jīng)典卷積神經(jīng)網(wǎng)絡(luò)resnet模塊訓(xùn)練
這篇文章主要介紹了Pytorch深度學(xué)習(xí)經(jīng)典卷積神經(jīng)網(wǎng)絡(luò)resnet模塊訓(xùn)練,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
python集成開發(fā)環(huán)境配置(pycharm)
本文是python快速進(jìn)階系列文章的第一篇,給大家介紹的是python集成開發(fā)環(huán)境pycharm的配置,有需要的小伙伴可以參考下2020-02-02
Python如何將jpg圖像修改大小并轉(zhuǎn)換為png
這篇文章主要介紹了Python如何將jpg圖像修改大小并轉(zhuǎn)換為png問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
Python打包代碼成exe可執(zhí)行文件的方法總結(jié)
將Python代碼打包成可執(zhí)行文件(.exe)是一種非常有效的解決方案,能夠使用戶無需安裝Python環(huán)境即可直接運行程序,本文整理了一些常見的方法,希望對大家有所幫助2024-10-10

