Python for循环背后的秘密:了解迭代器与生成器

 更新时间:2026年05月23日 10:40:17   作者:程序员榴莲  
本文详细解析了Python中for循环背后的机制,通过简单的示例帮助你理解迭代器与生成器的区别与用法,掌握这些概念,你可以更高效地地大量数据或延迟计算场景,立即阅读解锁更多Python技巧

本文基于一个简单的 Python 示例,系统梳理 for 循环、可迭代对象、迭代器、自定义迭代器以及生成器之间的关系。

前言

在 Python 中,我们经常会写这样的代码:

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

for num in nums:
    print(num)

这段代码看起来非常自然:从列表里一个一个取出数字,然后打印出来。

但如果继续往底层看,for 循环并不是凭空知道“下一个元素是谁”的。它背后依赖的核心机制,其实就是 迭代器

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

  • 为什么列表、字符串、字典都可以被 for 遍历;
  • iter()next() 到底在做什么;
  • 自定义对象如何支持循环;
  • yield 为什么能让普通函数变成生成器;
  • 生成器为什么适合处理大量数据或延迟计算。

for 循环背后的真实过程

先看一个普通的列表遍历:

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

for num in nums:
    print(num)

表面上看,for 循环会自动从 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

这里出现了两个非常关键的函数:

  • iter():把一个可迭代对象转换成迭代器;
  • next():从迭代器中取出下一个值。

当数据取完以后,迭代器会抛出 StopIteration 异常。for 循环内部会捕获这个异常,然后结束循环。

所以,for 循环的本质可以概括为:

先调用 iter() 得到迭代器,再不断调用 next() 取值,直到遇到 StopIteration 为止。

可迭代对象和迭代器的区别

在讲迭代器之前,很容易把两个概念混在一起:

  • 可迭代对象;
  • 迭代器。

它们看起来很像,但并不是同一个东西。

什么是可迭代对象

可迭代对象指的是可以被 iter() 处理的对象。

常见的可迭代对象包括:

list
tuple
dict
set
str
range

比如列表就是一个可迭代对象:

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

只要一个对象实现了 __iter__() 方法,它通常就可以被称为可迭代对象。

什么是迭代器

迭代器是可以被 next() 不断取值的对象。

一个标准的迭代器通常需要实现两个方法:

__iter__()
__next__()

其中:

  • __iter__() 返回迭代器对象本身;
  • __next__() 返回下一个值;
  • 如果没有更多数据,就抛出 StopIteration

换句话说:

可迭代对象负责“可以被遍历”,迭代器负责“真正一个一个吐出数据”。

自定义一个迭代器

下面我们自己实现一个简单的迭代器,让它依次返回 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("没有数据了")

使用方式如下:

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)

输出结果是:

1 2 3

这个类的核心在于 self.count

它负责记录当前迭代到哪里了。每次调用 next() 时,__next__() 方法都会让 count 加一,然后返回当前值。

count 超过 5 时,就说明数据已经取完,于是抛出 StopIteration

这也说明了迭代器的一个重要特点:

迭代器是有状态的,它会记住当前遍历到的位置。

用 for 循环遍历自定义迭代器

既然 MyIter 已经实现了 __iter__()__next__(),那么它也可以直接用于 for 循环:

for num in MyIter():
    print(num)

输出结果:

1
2
3
4
5

这再次证明了前面的结论:for 循环本质上就是在调用迭代器协议。

只要一个对象遵守这个协议,它就能被 for 循环消费。

迭代器的问题:写起来有点麻烦

虽然自定义迭代器的逻辑并不复杂,但完整写下来还是有些繁琐:

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

为了返回几个值,我们要写类、写状态、写 __iter__()、写 __next__(),还要手动处理 StopIteration

有没有更简单的写法?

有,这就是生成器。

生成器:用 yield 简化迭代器

生成器可以理解为一种更方便地创建迭代器的方式。

普通函数是这样的:

def func():
    print("开始执行了")

func()

调用 func() 时,函数会立刻执行。

但如果函数中出现了 yield,情况就不一样了:

def func():
    print("开始执行了")
    yield 1

generator = func()

这时调用 func() 并不会立刻执行函数体,而是返回一个生成器对象。

只有当我们调用 next() 时,函数才会真正开始执行:

print(next(generator))

执行过程是:

  1. 进入函数;
  2. 打印 "开始执行了"
  3. 遇到 yield 1
  4. 暂停函数执行;
  5. 1 返回给调用方。

yield 的关键点在于:它不仅返回值,还会暂停函数的执行状态。

下次继续调用 next() 时,函数会从上一次暂停的位置继续往下执行。

用生成器生成随机数

比如我们想生成一百个 1100 之间的随机数,可以这样写:

import random

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

for num in generator():
    print(num)

这里的 generator() 并不会一次性把一百个随机数全部创建出来。

它的执行方式是:

  • for 循环需要一个数;
  • 生成器运行到 yield
  • 返回一个随机数;
  • 暂停;
  • 下一轮循环再继续。

这就是生成器的优势:按需生成,节省内存

如果数据量很大,比如读取大文件、处理日志、生成无限序列,生成器会比一次性创建完整列表更合适。

迭代器和生成器的关系

可以这样理解:

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

生成器对象也可以被 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))

输出结果:

True
1
2
3

这说明生成器本身就是一个迭代器。

它帮我们省掉了手写 __iter__()__next__() 和状态管理的过程。

常见误区

误区一:列表本身就是迭代器

列表是可迭代对象,但列表本身不是迭代器。

nums = [1, 2, 3]

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

列表可以被 iter() 转换成迭代器:

iter_obj = iter(nums)

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

所以更准确的说法是:

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

误区二:yield 会立刻执行函数

包含 yield 的函数被调用时,不会立刻执行函数体。

def func():
    print("开始执行了")
    yield 1

g = func()

上面这段代码不会打印任何内容。

只有执行下面这行时,函数才会开始运行:

next(g)

误区三:StopIteration 是错误

StopIteration 并不一定代表程序出错。

在迭代器协议中,它是一种正常的结束信号。

当迭代器没有更多值时,就应该抛出 StopIteration,告诉调用方“数据已经取完了”。

for 循环会自动处理这个异常,所以我们平时很少直接看到它。

小结

本文从一个普通的 for 循环出发,逐步拆解了 Python 的迭代机制。

核心结论如下:

  • for 循环底层依赖 iter()next()
  • 可迭代对象是可以被 iter() 处理的对象;
  • 迭代器是可以被 next() 不断取值的对象;
  • 迭代器通过 __iter__()__next__() 实现;
  • StopIteration 用来表示迭代结束;
  • 生成器通过 yield 简化了迭代器的编写;
  • 生成器按需生成数据,适合处理大数据量或延迟计算场景。

如果用一句话总结:

迭代器是 Python 循环机制的底层基础,而生成器是编写迭代器的优雅方式。

到此这篇关于Python for循环背后的秘密:了解迭代器与生成器的文章就介绍到这了,更多相关Python中for循环内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python调用stitcher类自动实现多个图像拼接融合功能

    python调用stitcher类自动实现多个图像拼接融合功能

    这篇文章主要介绍了python调用stitcher类自动实现多个图像拼接融合功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • Python anaconda安装库命令详解

    Python anaconda安装库命令详解

    这篇文章主要介绍了Python anaconda安装库命令详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10
  • 使用Python通过简单操作设置PDF文档属性

    使用Python通过简单操作设置PDF文档属性

    PDF文档属性是嵌入在PDF文档中的一些与文档有关的信息,这篇文章主要为大家介绍了如何使用Python通过简单的操作设置PDF文档属性,需要的可以参考下
    2023-11-11
  • python利用xlsxwriter模块 操作 Excel

    python利用xlsxwriter模块 操作 Excel

    这篇文章主要介绍了python利用xlsxwriter模块 操作 Excel,帮助大家更好的利用python处理表格,提高办公效率,感兴趣的朋友可以了解下
    2020-10-10
  • TensorFlow实现批量归一化操作的示例

    TensorFlow实现批量归一化操作的示例

    这篇文章主要介绍了TensorFlow实现批量归一化操作的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • 详解Python3中字符串中的数字提取方法

    详解Python3中字符串中的数字提取方法

    这篇文章主要介绍了详解Python3中字符串中的数字提取方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Python3使用mysql-connector模块连接MySQL数据库

    Python3使用mysql-connector模块连接MySQL数据库

    Python作为一种强大的编程语言,也因其简洁的语法和丰富的库支持而备受青睐,本文将介绍如何在Python3中使用mysql-connector模块连接到MySQL数据库,并执行基本的数据库操作,感兴趣的朋友一起看看吧
    2026-02-02
  • python pandas时序处理相关功能详解

    python pandas时序处理相关功能详解

    这篇文章主要介绍了python pandas时序处理相关功能详解的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • 浅谈Django Admin的初步使用

    浅谈Django Admin的初步使用

    本文主要介绍了浅谈Django Admin的初步使用 ,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Python对文件和目录进行操作的方法(file对象/os/os.path/shutil 模块)

    Python对文件和目录进行操作的方法(file对象/os/os.path/shutil 模块)

    下面小编就为大家带来一篇Python对文件和目录进行操作的方法(file对象/os/os.path/shutil 模块)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05

最新评论