最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python?for循環(huán)背后的秘密:了解迭代器與生成器

 更新時(shí)間:2026年05月23日 10:40:17   作者:程序員榴蓮  
本文詳細(xì)解析了Python中for循環(huán)背后的機(jī)制,通過簡單的示例幫助你理解迭代器與生成器的區(qū)別與用法,掌握這些概念,你可以更高效地地大量數(shù)據(jù)或延遲計(jì)算場景,立即閱讀解鎖更多Python技巧

本文基于一個(gè)簡單的 Python 示例,系統(tǒng)梳理 for 循環(huán)、可迭代對(duì)象、迭代器、自定義迭代器以及生成器之間的關(guān)系。

前言

在 Python 中,我們經(jīng)常會(huì)寫這樣的代碼:

nums = [1, 2, 3, 4, 5]

for num in nums:
    print(num)

這段代碼看起來非常自然:從列表里一個(gè)一個(gè)取出數(shù)字,然后打印出來。

但如果繼續(xù)往底層看,for 循環(huán)并不是憑空知道“下一個(gè)元素是誰”的。它背后依賴的核心機(jī)制,其實(shí)就是 迭代器

理解迭代器之后,我們就能更清楚地理解 Python 中很多常見概念,比如:

  • 為什么列表、字符串、字典都可以被 for 遍歷;
  • iter()next() 到底在做什么;
  • 自定義對(duì)象如何支持循環(huán);
  • yield 為什么能讓普通函數(shù)變成生成器;
  • 生成器為什么適合處理大量數(shù)據(jù)或延遲計(jì)算。

for 循環(huán)背后的真實(shí)過程

先看一個(gè)普通的列表遍歷:

nums = [1, 2, 3, 4, 5]

for num in nums:
    print(num)

表面上看,for 循環(huán)會(huì)自動(dòng)從 nums 中取值。但它的底層邏輯大致可以理解為下面這樣:

nums = [1, 2, 3, 4, 5]
iter_obj = iter(nums)

while True:
    try:
        next_num = next(iter_obj)
        print(next_num)
    except StopIteration:
        break

這里出現(xiàn)了兩個(gè)非常關(guān)鍵的函數(shù):

  • iter():把一個(gè)可迭代對(duì)象轉(zhuǎn)換成迭代器;
  • next():從迭代器中取出下一個(gè)值。

當(dāng)數(shù)據(jù)取完以后,迭代器會(huì)拋出 StopIteration 異常。for 循環(huán)內(nèi)部會(huì)捕獲這個(gè)異常,然后結(jié)束循環(huán)。

所以,for 循環(huán)的本質(zhì)可以概括為:

先調(diào)用 iter() 得到迭代器,再不斷調(diào)用 next() 取值,直到遇到 StopIteration 為止。

可迭代對(duì)象和迭代器的區(qū)別

在講迭代器之前,很容易把兩個(gè)概念混在一起:

  • 可迭代對(duì)象;
  • 迭代器。

它們看起來很像,但并不是同一個(gè)東西。

什么是可迭代對(duì)象

可迭代對(duì)象指的是可以被 iter() 處理的對(duì)象。

常見的可迭代對(duì)象包括:

list
tuple
dict
set
str
range

比如列表就是一個(gè)可迭代對(duì)象:

nums = [1, 2, 3]
iter_obj = iter(nums)

只要一個(gè)對(duì)象實(shí)現(xiàn)了 __iter__() 方法,它通常就可以被稱為可迭代對(duì)象。

什么是迭代器

迭代器是可以被 next() 不斷取值的對(duì)象。

一個(gè)標(biāo)準(zhǔn)的迭代器通常需要實(shí)現(xiàn)兩個(gè)方法:

__iter__()
__next__()

其中:

  • __iter__() 返回迭代器對(duì)象本身;
  • __next__() 返回下一個(gè)值;
  • 如果沒有更多數(shù)據(jù),就拋出 StopIteration。

換句話說:

可迭代對(duì)象負(fù)責(zé)“可以被遍歷”,迭代器負(fù)責(zé)“真正一個(gè)一個(gè)吐出數(shù)據(jù)”。

自定義一個(gè)迭代器

下面我們自己實(shí)現(xiàn)一個(gè)簡單的迭代器,讓它依次返回 15

class MyIter:
    def __init__(self):
        self.count = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.count += 1
        if self.count <= 5:
            return self.count
        else:
            raise StopIteration("沒有數(shù)據(jù)了")

使用方式如下:

my_iter = MyIter()
my_iter_obj = iter(my_iter)

num1 = next(my_iter_obj)
num2 = next(my_iter_obj)
num3 = next(my_iter_obj)

print(num1, num2, num3)

輸出結(jié)果是:

1 2 3

這個(gè)類的核心在于 self.count。

它負(fù)責(zé)記錄當(dāng)前迭代到哪里了。每次調(diào)用 next() 時(shí),__next__() 方法都會(huì)讓 count 加一,然后返回當(dāng)前值。

當(dāng) count 超過 5 時(shí),就說明數(shù)據(jù)已經(jīng)取完,于是拋出 StopIteration。

這也說明了迭代器的一個(gè)重要特點(diǎn):

迭代器是有狀態(tài)的,它會(huì)記住當(dāng)前遍歷到的位置。

用 for 循環(huán)遍歷自定義迭代器

既然 MyIter 已經(jīng)實(shí)現(xiàn)了 __iter__()__next__(),那么它也可以直接用于 for 循環(huán):

for num in MyIter():
    print(num)

輸出結(jié)果:

1
2
3
4
5

這再次證明了前面的結(jié)論:for 循環(huán)本質(zhì)上就是在調(diào)用迭代器協(xié)議。

只要一個(gè)對(duì)象遵守這個(gè)協(xié)議,它就能被 for 循環(huán)消費(fèi)。

迭代器的問題:寫起來有點(diǎn)麻煩

雖然自定義迭代器的邏輯并不復(fù)雜,但完整寫下來還是有些繁瑣:

class MyIter:
    def __init__(self):
        self.count = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.count += 1
        if self.count <= 5:
            return self.count
        else:
            raise StopIteration

為了返回幾個(gè)值,我們要寫類、寫狀態(tài)、寫 __iter__()、寫 __next__(),還要手動(dòng)處理 StopIteration。

有沒有更簡單的寫法?

有,這就是生成器。

生成器:用 yield 簡化迭代器

生成器可以理解為一種更方便地創(chuàng)建迭代器的方式。

普通函數(shù)是這樣的:

def func():
    print("開始執(zhí)行了")

func()

調(diào)用 func() 時(shí),函數(shù)會(huì)立刻執(zhí)行。

但如果函數(shù)中出現(xiàn)了 yield,情況就不一樣了:

def func():
    print("開始執(zhí)行了")
    yield 1

generator = func()

這時(shí)調(diào)用 func() 并不會(huì)立刻執(zhí)行函數(shù)體,而是返回一個(gè)生成器對(duì)象。

只有當(dāng)我們調(diào)用 next() 時(shí),函數(shù)才會(huì)真正開始執(zhí)行:

print(next(generator))

執(zhí)行過程是:

  1. 進(jìn)入函數(shù);
  2. 打印 "開始執(zhí)行了"
  3. 遇到 yield 1;
  4. 暫停函數(shù)執(zhí)行;
  5. 1 返回給調(diào)用方。

yield 的關(guān)鍵點(diǎn)在于:它不僅返回值,還會(huì)暫停函數(shù)的執(zhí)行狀態(tài)。

下次繼續(xù)調(diào)用 next() 時(shí),函數(shù)會(huì)從上一次暫停的位置繼續(xù)往下執(zhí)行。

用生成器生成隨機(jī)數(shù)

比如我們想生成一百個(gè) 1100 之間的隨機(jī)數(shù),可以這樣寫:

import random

def generator():
    for i in range(100):
        yield random.randint(1, 100)

for num in generator():
    print(num)

這里的 generator() 并不會(huì)一次性把一百個(gè)隨機(jī)數(shù)全部創(chuàng)建出來。

它的執(zhí)行方式是:

  • for 循環(huán)需要一個(gè)數(shù);
  • 生成器運(yùn)行到 yield;
  • 返回一個(gè)隨機(jī)數(shù);
  • 暫停;
  • 下一輪循環(huán)再繼續(xù)。

這就是生成器的優(yōu)勢:按需生成,節(jié)省內(nèi)存。

如果數(shù)據(jù)量很大,比如讀取大文件、處理日志、生成無限序列,生成器會(huì)比一次性創(chuàng)建完整列表更合適。

迭代器和生成器的關(guān)系

可以這樣理解:

生成器是一種特殊的迭代器。

生成器對(duì)象也可以被 iter() 處理,也可以被 next() 取值。

例如:

def nums():
    yield 1
    yield 2
    yield 3

g = nums()

print(iter(g) is g)
print(next(g))
print(next(g))
print(next(g))

輸出結(jié)果:

True
1
2
3

這說明生成器本身就是一個(gè)迭代器。

它幫我們省掉了手寫 __iter__()、__next__() 和狀態(tài)管理的過程。

常見誤區(qū)

誤區(qū)一:列表本身就是迭代器

列表是可迭代對(duì)象,但列表本身不是迭代器。

nums = [1, 2, 3]

print(hasattr(nums, "__iter__"))   # True
print(hasattr(nums, "__next__"))   # False

列表可以被 iter() 轉(zhuǎn)換成迭代器:

iter_obj = iter(nums)

print(hasattr(iter_obj, "__iter__"))  # True
print(hasattr(iter_obj, "__next__"))  # True

所以更準(zhǔn)確的說法是:

列表是可迭代對(duì)象,iter(列表) 得到的對(duì)象才是迭代器。

誤區(qū)二:yield 會(huì)立刻執(zhí)行函數(shù)

包含 yield 的函數(shù)被調(diào)用時(shí),不會(huì)立刻執(zhí)行函數(shù)體。

def func():
    print("開始執(zhí)行了")
    yield 1

g = func()

上面這段代碼不會(huì)打印任何內(nèi)容。

只有執(zhí)行下面這行時(shí),函數(shù)才會(huì)開始運(yùn)行:

next(g)

誤區(qū)三:StopIteration 是錯(cuò)誤

StopIteration 并不一定代表程序出錯(cuò)。

在迭代器協(xié)議中,它是一種正常的結(jié)束信號(hào)。

當(dāng)?shù)鳑]有更多值時(shí),就應(yīng)該拋出 StopIteration,告訴調(diào)用方“數(shù)據(jù)已經(jīng)取完了”。

for 循環(huán)會(huì)自動(dòng)處理這個(gè)異常,所以我們平時(shí)很少直接看到它。

小結(jié)

本文從一個(gè)普通的 for 循環(huán)出發(fā),逐步拆解了 Python 的迭代機(jī)制。

核心結(jié)論如下:

  • for 循環(huán)底層依賴 iter()next()
  • 可迭代對(duì)象是可以被 iter() 處理的對(duì)象;
  • 迭代器是可以被 next() 不斷取值的對(duì)象;
  • 迭代器通過 __iter__()__next__() 實(shí)現(xiàn);
  • StopIteration 用來表示迭代結(jié)束;
  • 生成器通過 yield 簡化了迭代器的編寫;
  • 生成器按需生成數(shù)據(jù),適合處理大數(shù)據(jù)量或延遲計(jì)算場景。

如果用一句話總結(jié):

迭代器是 Python 循環(huán)機(jī)制的底層基礎(chǔ),而生成器是編寫迭代器的優(yōu)雅方式。

到此這篇關(guān)于Python for循環(huán)背后的秘密:了解迭代器與生成器的文章就介紹到這了,更多相關(guān)Python中for循環(huán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

建始县| 旌德县| 林口县| 舒兰市| 崇文区| 井冈山市| 嘉义市| 平罗县| 新田县| 郎溪县| 华蓥市| 正阳县| 沽源县| 文成县| 安图县| 延庆县| 肃南| 云霄县| 宁津县| 澎湖县| 安丘市| 霍林郭勒市| 正宁县| 荣昌县| 中卫市| 建宁县| 姚安县| 孝昌县| 肇庆市| 霍林郭勒市| 沂南县| 定南县| 拜泉县| 永年县| 泽州县| 阿拉善右旗| 广丰县| 青海省| 米林县| 清丰县| 乌什县|