迭代器與生成器:Python 中的高效數據遍歷機制

一、迭代器和生成器的基本概念

1. 迭代器的定義和工作原理

(1)迭代器的概念

迭代器(Iterator) 是 Python 中一種支持逐個訪問元素的對象,它遵循 迭代器協議(Iterator Protocol),即實現了兩個特殊方法:

  • __iter__():返回迭代器對象本身。
  • __next__():返回容器中的下一個元素;當沒有更多元素時,拋出 StopIteration 異常。

迭代器提供了一種統一的方式來遍歷各種可迭代對象(如列表、元組、字典、集合、文件等),而無需關心其內部結構。它實現了“用同一種方式遍歷不同數據結構”的設計思想。

注意:range() 并不是一個迭代器,而是一個 可迭代對象(iterable)。調用 iter(range(5)) 才會得到一個迭代器。

(2)迭代器的特點
  1. 單向遍歷:只能向前移動,不能回退或重置(除非重新創建)。
  2. 狀態保持:迭代器自身維護當前遍歷位置的狀態。
  3. 惰性求值:許多迭代器采用惰性計算策略,按需生成數據,節省內存。
  4. 一次性使用:一旦遍歷完成(觸發 StopIteration),該迭代器通常無法再次使用(除非是特殊設計的可重置迭代器)。
(3)迭代器的使用方式
  • 使用 for 循環自動調用 __iter__()__next__()
  • 手動使用 next(iterator) 獲取下一個元素
my_list = [1, 2, 3]
it = iter(my_list)
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# print(next(it))  # StopIteration
(4)迭代器的優勢
  • 內存效率高:不一次性加載所有數據到內存。
  • 適用于大數據流:如讀取大文件、網絡流、傳感器數據等。
  • 統一接口:為不同數據結構提供一致的遍歷方式。

2. 生成器的定義和特點

生成器(Generator) 是一種特殊的迭代器,由生成器函數或生成器表達式創建。它自動實現了 __iter__()__next__() 方法,并能“記住”函數執行的狀態。

(1)生成器的核心機制:yield
  • yield 關鍵字使函數暫停并返回一個值,下次調用 next() 時從暫停處繼續執行。
  • return 不同,yield 不終止函數,而是“掛起”函數狀態。
def count_up_to(n):i = 1while i <= n:yield ii += 1gen = count_up_to(3)
print(list(gen))  # [1, 2, 3]
(2)生成器的特點
  1. 自動實現迭代器協議:無需手動編寫 __iter____next__
  2. 惰性計算:按需生成值,極大節省內存。
  3. 狀態保存:函數局部變量在 yield 后仍保留。
  4. 簡潔語法:代碼更清晰,易于編寫復雜迭代邏輯。

3. 迭代器與生成器的區別與聯系

特性迭代器生成器
創建方式實現 __iter____next__使用 yield 函數 或 (expr) 表達式
編寫復雜度較高,需手動管理狀態簡單,函數式風格
內存占用通常較低極低(函數棧 + 局部變量)
可重用性一般不可重用一般不可重用
是否為迭代器是(生成器是迭代器的子集)
惰性計算支持支持
調試難度相對容易狀態隱式,調試略難

聯系
所有生成器都是迭代器,但并非所有迭代器都是生成器。
生成器是對迭代器的高級封裝,簡化了迭代器的創建過程。


二、迭代器的實現和使用

1. 使用 iter()next() 手動操作

data = [10, 20, 30]
it = iter(data)
while True:try:value = next(it)print(value)except StopIteration:break

2. 自定義迭代器類

class CountDown:def __init__(self, start):self.start = startdef __iter__(self):return selfdef __next__(self):if self.start <= 0:raise StopIterationself.start -= 1return self.start + 1for n in CountDown(3):print(n)  # 3, 2, 1

3. 內置迭代工具的使用

Python 提供了豐富的內置迭代工具,位于 itertools 模塊中:

  • enumerate(iterable):返回索引和值
  • zip(*iterables):并行遍歷多個序列
  • itertools.count():無限計數器
  • itertools.cycle():循環遍歷
  • itertools.chain():連接多個迭代器
from itertools import countcounter = count(1, 2)  # 1, 3, 5, ...
print(next(counter))  # 1
print(next(counter))  # 3

三、生成器的實現和使用

1. 生成器函數與 yield

def fibonacci():a, b = 0, 1while True:yield aa, b = b, a + bfib = fibonacci()
print([next(fib) for _ in range(10)])  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

2. 生成器表達式

語法類似于列表推導式,但使用 () 而非 [],返回生成器對象。

gen = (x**2 for x in range(5))
print(list(gen))  # [0, 1, 4, 9, 16]

優點:內存占用極小,適合大數據集處理。

3. 惰性計算特性

生成器只在需要時才計算下一個值,非常適合處理以下場景:

  • 大文件逐行讀取
  • 數據流處理
  • 無限序列生成
def read_large_file(file_path):with open(file_path, 'r') as f:for line in f:yield line.strip()

四、實際應用場景

1. 處理大數據集時的內存優化

使用生成器避免將整個數據集加載到內存中:

#  危險:可能耗盡內存
lines = [line.strip() for line in open('huge_file.txt')]#  安全:逐行處理
def process_lines(filename):with open(filename) as f:for line in f:yield clean(line)for line in process_lines('huge_file.txt'):print(line)

2. 實現無限序列

def natural_numbers():n = 1while True:yield nn += 1nums = natural_numbers()
print([next(nums) for _ in range(5)])  # [1, 2, 3, 4, 5]

3. 協程與異步編程中的應用

生成器曾是 Python 協程的基礎(@asyncio.coroutine + yield from),雖然后來被 async/await 取代,但理解生成器對掌握異步編程仍有幫助。

def echo():while True:received = yieldprint(f"Received: {received}")e = echo()
next(e)  # 啟動生成器
e.send("Hello")  # Received: Hello

五、性能對比與注意事項

1. 性能對比

場景推薦方式原因
小數據、需多次遍歷列表支持索引、可重復使用
大數據、單次遍歷生成器內存友好
復雜狀態控制自定義迭代器更靈活的狀態管理
快速構建簡單迭代生成器表達式語法簡潔

2. 何時選擇迭代器或生成器?

  • 選擇生成器:邏輯清晰、函數式風格、一次性遍歷、內存敏感。
  • 選擇自定義迭代器:需要復雜狀態管理、支持重置、多次遍歷、面向對象設計。

3. 常見錯誤與調試技巧

  • 錯誤1:重復使用已耗盡的生成器
gen = (x for x in range(3))
print(list(gen))  # [0, 1, 2]
print(list(gen))  # [] —— 已耗盡!

解決方案:重新創建生成器或轉為列表(犧牲內存)。

  • 錯誤2:忘記啟動協程(使用 send 前未調用 next
gen = echo()
# gen.send("Hi")  # TypeError: can't send non-None value to a just-started generator
next(gen)  # 或 gen.send(None)
gen.send("Hi")
  • 調試建議:
  • 使用 itertools.tee() 復制迭代器用于調試(注意內存開銷)
  • 將生成器轉為列表進行測試(僅限小數據)

六、進階話題

1. 生成器的 sendthrowclose 方法

  • send(value):向生成器發送值,作為 yield 表達式的返回值
  • throw(exc):在生成器內引發異常
  • close():關閉生成器,觸發 GeneratorExit
def accumulator():total = 0while True:value = yield totalif value is not None:total += valueacc = accumulator()
print(next(acc))      # 0
print(acc.send(10))   # 10
print(acc.send(5))    # 15
acc.close()

2. 使用 yield from 簡化嵌套生成器

yield from 可以將子生成器的值直接“委托”給外層生成器。

def sub_generator():yield "a"yield "b"def main_generator():yield 1yield from sub_generator()yield 2list(main_generator())  # [1, 'a', 'b', 2]

3. 結合 asyncio 實現異步生成器

Python 3.6+ 支持異步生成器,可用于異步數據流處理。

import asyncioasync def async_counter():for i in range(3):await asyncio.sleep(1)yield iasync def main():async for num in async_counter():print(num)# asyncio.run(main())

七、總結

1. 核心優勢

  • 內存效率:惰性計算避免一次性加載大量數據。
  • 代碼簡潔:生成器讓復雜迭代邏輯變得清晰。
  • 統一接口:迭代器協議使遍歷操作標準化。
  • 擴展性強:支持無限序列、協程、異步等高級模式。

2. 實際開發中的推薦實踐

  • 優先使用生成器處理大數據或流式數據。
  • 使用生成器表達式替代列表推導式(當只需遍歷一次時)。
  • 避免對生成器做多次遍歷,必要時緩存結果。
  • 在需要復雜狀態管理時,考慮自定義迭代器類。
  • 善用 itertools 模塊提高開發效率。

結語
掌握迭代器與生成器是成為 Python 高級開發者的重要一步。它們不僅是語言特性,更是一種編程思維——按需計算、延遲執行、資源節約。合理運用,可顯著提升程序性能與可維護性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/94664.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/94664.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/94664.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java 發送 HTTP POST請求教程

Java 發送 HTTP POST 請求的方法使用 HttpURLConnection&#xff08;原生 Java 支持&#xff09; 創建一個 HttpURLConnection 對象&#xff0c;設置請求方法為 POST&#xff0c;并寫入請求體數據。以下是一個簡單示例&#xff1a;import java.io.OutputStream; import java.ne…

計算機英語詳細總結

計算機英語作為信息技術領域的專用語言&#xff0c;融合了專業術語、縮寫、行業表達及技術文檔規范&#xff0c;是學習編程、從事 IT 工作的核心工具。以下從核心分類、應用場景、學習方法三方面詳細梳理&#xff1a;一、核心術語分類與高頻詞匯1. 編程語言與語法基礎基礎概念&…

「日拱一碼」045 機器學習-因果發現算法

目錄 基于約束的方法 (Constraint-based) 基于評分的方法 (Score-based) 基于函數因果模型的方法 (Functional Causal Models) 基于梯度的方法 (Gradient-based) 因果發現是機器學習中一個重要的研究方向&#xff0c;它旨在從觀測數據中推斷變量之間的因果關系 基于約束的…

S7-1200 串行通信介紹

S7-1200 串行通信S7-1200支持的串行通訊方式點對點&#xff08;PtP&#xff09;通信Modbus 主從通信USS 通信名稱CM 1241 RS232CM 1241 RS422/485CB 1241 RS485訂貨號6ES7241-1AH32-0XB06ES7241-1CH32-0XB06ES7241-1CH30-1XB0通訊口類型RS232RS422/RS485RS485波特率(bps)300 ;6…

達夢包含OR條件的SQL特定優化----INJECT-HINT優化方法

Time:2025/08/07Author:skatexg應用迭代發版須執行如下動作 1、按目標需求全面壓力測試&#xff0c;優化潛在慢SQL或設置特殊優化參數(如&#xff1a;OPTIMIZER_OR_NBEXP) 2、達夢數據庫有數據導入&#xff0c;必須收集統計信息達夢使用SF_INJECT_HINT系統函數對指定SQL增加HIN…

JSqlParser學習筆記 快速使用JSqlParser

文章目錄前言本章節源碼官方文檔信息認識JSqlParserHow it works? 它是如何工作的&#xff1f;知識點關于statement實際應用場景引入依賴Parser 解析SQL解析sql語句解析sql區分sql類型分析增刪改查語句查詢語句認識PlainSelect示范新增語句了解Insert常用方法示范更新語句刪除…

Godot ------ 中級人物血條制作01

Godot ------ 中級人物血條制作 引言 正文 傳統血條制作 方格血條制作 傳奇,暗黑破環神類血條顯示 引言 在此之前,我們分四篇介紹了 Godot 中人物血條的制作,但是我們用到的都是比較基礎的節點 ProgressBar,本文我們將介紹另外一種相對高級的節點 TextureProgressBar。 正…

《WebPages 類:構建高效網頁的基石》

《WebPages 類&#xff1a;構建高效網頁的基石》 引言 在互聯網高速發展的今天&#xff0c;網頁作為信息傳遞和交互的重要載體&#xff0c;其重要性不言而喻。而一個高效、美觀、易用的網頁&#xff0c;往往離不開一個優秀的網頁類的設計。本文將深入探討WebPages類的概念、特點…

直播預告|鴻蒙生態下的 Flutter 開發實戰

《開發者 面對面》堅果派特輯直播&#xff08;二&#xff09;來了&#xff01;在鴻蒙系統日益完善的今天&#xff0c;Flutter 開發者將迎來哪些新機遇&#xff1f;在 HarmonyOS 上開發 Flutter&#xff0c;如何實現高效適配與生態融合&#xff1f;本期「開發者面對面」堅果派特…

web前端結合Microsoft Office Online 在線預覽,vue實現(PPT、Word、Excel、PDF等)

web前端結合Microsoft Office Online 在線預覽&#xff0c;vue實現&#xff08;PPT、Word、Excel、PDF等&#xff09; 什么是 Microsoft Office Online 預覽服務 Microsoft Office Online 預覽服務是由微軟提供的免費在線文檔預覽工具&#xff0c;通過簡單的 URL 參數配置&am…

安卓手機用久了會出現卡頓,為什么?

安卓手機用久了出現卡頓&#xff0c;主要與內存不足、系統機制特性、硬件老化、軟件沖突與冗余、使用習慣不當五大核心因素相關。以下是具體原因及針對性解決方案&#xff1a;一、卡頓核心原因分析內存不足運行內存&#xff08;RAM&#xff09;被占用&#xff1a;安卓應用默認在…

以 Eland 玩轉 Elasticsearch 8.12 Learning-to-Rank

1 為什么要在 Elasticsearch 上做 LTR&#xff1f; 適用版本&#xff1a; Elasticsearch ≥ 8.12.0 前置條件&#xff1a; 需擁有包含 “Serverless LTR” 的訂閱等級&#xff08;詳見官方訂閱矩陣&#xff09; 技術棧&#xff1a; Elasticsearch Python Eland XGBoost / Li…

OpenCV入門:圖像處理基礎教程

OpenCV簡介 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一個開源的計算機視覺和機器學習庫。它包含超過2500種優化算法&#xff0c;涵蓋圖像處理、物體識別、人臉檢測、3D重建、視頻分析等任務。 核心功能 圖像處理&#xff1a;濾波、邊緣檢測、幾…

影響內容傳播速度的因素有哪些?

內容的傳播速度是我們在衡量營銷效果時的重要指標。傳播速度越快&#xff0c;越能幫助品牌迅速覆蓋目標受眾&#xff0c;在短時間內提升影響力。影響內容傳播速度的方式來自多個方面&#xff0c;下面就讓我們一同來了解下這其中的因素。一、觀點價值觀點是否具有價值&#xff0…

css動態樣式

使用scss通過變量設置css動態樣式<template><div><!-- 方式一 --><p v-for"(item, index) in dataList" :key"index" :style"{--color: item.color}" >{{item.name}}</p><!-- 方式二 --><p v-for"(…

開源流媒體服務器ZLMediaKit 的Java Api實現的Java版ZLMediaKit流媒體服務器-二開視頻對話

安全性&#xff1a;使用了WSS&#xff08;WebSocket Secure&#xff09;協議確保通信安全 兼容性&#xff1a;支持現代瀏覽器的WebRTC功能 信令機制&#xff1a;通過WebSocket進行信令交換&#xff0c;確保連接建立 媒體傳輸&#xff1a;使用STUN服務器進行NAT穿透&#xff0c;…

mariadb10.3.35備份腳本

一、創建備份用戶[(none)]> create user buserlocalhost identified by tmrQ;[(none)]> GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO buserlocalhost;[(none)]> flush privileges;二、腳本# cat mysql_bask.sh #!/bin/bash # MariaDB 10.3.35…

W3D引擎游戲開發----從入門到精通【22】

配置完成基本DT物體項后&#xff0c;在這個DT物體項中開始添加這個玩家的動畫信息&#xff0c;如下所示。UseAnim設置是否使用動畫功能&#xff0c;這里開啟。AnimTypeN設置總共的動畫類型數&#xff0c;當前只有一個待機動畫&#xff0c;因此設置為1。AnimType1FrameN設置1號動…

在我國申請注冊的商標在國外可以用不!

近日一個網友找到普推知產商標老楊&#xff0c;問在我國申請注冊商標在新加坡和歐盟可以用不&#xff0c;當然用不成&#xff0c;根據商標法的地域性原則&#xff0c;商標權保護限于注冊地&#xff0c;馳名商標享有部分跨國保護&#xff0c;但是這個要有所在國相關法律證據。如…

在開發板上畫出一個2048棋盤的矩陣

#include “head.h"int* p lcd NULL; //顯示屏內存映射的起始地址int g lcd width; //LCD顯示屏的寬度int g lcd high ; //LCD顯示屏的高度int g lcd bpp; //每個像素點所占的比特位//int x:屏的X軸&#xff08;寬度、列&#xff09;坐標//int y:屏幕y軸&#xff08;高度、…