在学 Python 的过程中,我们常常会碰到"迭代器"这个词。它听起来有点抽象,其实本质就是一种"能一个一个取值"的东西。本文就来系统讲讲迭代器,帮你把这个概念吃透。
参考文章:
目录
- 什么是可迭代对象(Iterable)?
- 什么是迭代器(Iterator)?
iter()
和next()
的用法- for 循环背后的迭代器机制
- 为什么需要迭代器?
- 自定义一个迭代器类
- 使用生成器简化迭代器
isinstance()
判断是不是迭代器- 可迭代但不是迭代器的对象
- 小结和注意事项
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
,它是控制"结束"的信号