Python 迭代器:从入门到精通

在学 Python 的过程中,我们常常会碰到"迭代器"这个词。它听起来有点抽象,其实本质就是一种"能一个一个取值"的东西。本文就来系统讲讲迭代器,帮你把这个概念吃透。

参考文章:

目录

  1. 什么是可迭代对象(Iterable)?
  2. 什么是迭代器(Iterator)?
  3. iter()next() 的用法
  4. for 循环背后的迭代器机制
  5. 为什么需要迭代器?
  6. 自定义一个迭代器类
  7. 使用生成器简化迭代器
  8. isinstance() 判断是不是迭代器
  9. 可迭代但不是迭代器的对象
  10. 小结和注意事项

1. 什么是可迭代对象(Iterable)?

可迭代对象指的是能被一个个遍历的对象 ,比如列表、字符串、元组、集合、字典等等。判断一个对象是否可迭代,可以用 collections.abc.Iterable 来检查:

python 复制代码
from collections.abc import Iterable

print(isinstance([1, 2, 3], Iterable))  # True
print(isinstance(123, Iterable))       # False

这些对象可以用 for 循环,是因为它们都实现了 __iter__() 方法。


2. 什么是迭代器(Iterator)?

迭代器是一个可以记住当前遍历位置的对象 ,从它那里你可以不停地 next() 出下一个值,直到取不到为止(会抛出 StopIteration 异常)。

一个对象如果:

  • 实现了 __iter__() 方法,返回自身
  • 实现了 __next__() 方法

那它就是一个迭代器。

python 复制代码
from collections.abc import Iterator

print(isinstance(iter([1, 2, 3]), Iterator))  # True

3. iter()next() 的用法

Python 提供了两个内置函数和迭代器打交道:

  • iter(obj):把一个可迭代对象变成迭代器
  • next(iterator):从迭代器里取出下一个值

示例:

python 复制代码
nums = [10, 20, 30]
it = iter(nums)

print(next(it))  # 10
print(next(it))  # 20
print(next(it))  # 30
# print(next(it))  # 报错:StopIteration

4. for 循环背后的迭代器机制

你用惯的 for 循环,其实背后就是在用迭代器。来看下"真相":

python 复制代码
for x in [1, 2, 3]:
    print(x)

其实等价于:

python 复制代码
it = iter([1, 2, 3])
while True:
    try:
        x = next(it)
        print(x)
    except StopIteration:
        break

是不是瞬间明白了?


5. 为什么需要迭代器?

迭代器有两个大优点:

  • 惰性计算:只有在需要下一个值的时候才去计算,节省内存
  • 适合处理大型数据流:比如处理几百 GB 的日志文件时,就不能一次性全部加载到内存中,这时候迭代器就派上用场了

6. 自定义一个迭代器类

我们可以自定义一个类来模拟迭代器的行为,比如实现一个生成斐波那契数列的迭代器:

python 复制代码
class Fibonacci:
    def __init__(self, max):
        self.max = max
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.a > self.max:
            raise StopIteration
        value = self.a
        self.a, self.b = self.b, self.a + self.b
        return value

fib = Fibonacci(100)
for num in fib:
    print(num, end=' ')

输出:0 1 1 2 3 5 8 13 21 34 55 89


7. 使用生成器简化迭代器

虽然可以用类实现迭代器,但有时候写起来太麻烦。Python 提供了更简洁的方式:生成器(generator)

yield 写个斐波那契生成器:

python 复制代码
def fibonacci(max):
    a, b = 0, 1
    while a <= max:
        yield a
        a, b = b, a + b

for n in fibonacci(100):
    print(n, end=' ')

是不是比类清爽多了?


8. isinstance() 判断是不是迭代器

快速判断对象的类型是否是可迭代或迭代器:

python 复制代码
from collections.abc import Iterable, Iterator

print(isinstance([1, 2, 3], Iterable))  # True
print(isinstance([1, 2, 3], Iterator))  # False

it = iter([1, 2, 3])
print(isinstance(it, Iterator))        # True

9. 可迭代但不是迭代器的对象

很多常见的结构(比如 list、str)是"可迭代的",但它们不是"迭代器":

python 复制代码
lst = [1, 2, 3]
print(hasattr(lst, '__iter__'))   # True
print(hasattr(lst, '__next__'))   # False

不过你可以随时把它变成迭代器:

python 复制代码
it = iter(lst)
print(next(it))  # 1

10. 小结

  • 所有能被 for 遍历的都是"可迭代对象"
  • 迭代器是"可迭代对象"的一种升级版,它支持 next()、惰性计算
  • 自定义迭代器要写 __iter__()__next__() 方法
  • 想省事就用生成器 yield,写起来又简洁又优雅
  • 一定要注意 StopIteration,它是控制"结束"的信号
相关推荐
中等生1 小时前
Python的隐形枷锁:GIL如何"绑架"了你的多线程梦想
后端·python
电商数据girl1 小时前
关于私域电商网站,接入电商API数据接口示例
运维·开发语言·网络·python·json·php
Ly2020Wj2 小时前
pytorch入门3:使用pytorch进行多输出手写数据集模型预测
人工智能·pytorch·python
码界筑梦坊2 小时前
90-基于Flask的中国博物馆数据可视化分析系统
python·信息可视化·flask
七七软件开发2 小时前
无人共享 app 系统架构分析
java·python·小程序·系统架构·php
WaterRun2 小时前
一个极简极易用, "即读即用"的Python存储库介绍: SimpSave
python
WaterRun2 小时前
使用Python合并B站缓存视频(至.MP4): 库biliffm4s介绍
python
gonghw4032 小时前
Python中变量之间赋值的理解
python
疯狂的Alex2 小时前
未来20年哪几种编程语言会保持优势?哪几种编程语言会得到更广泛的应用?
java·开发语言·c++·python·c#