在Python编程中,迭代器是一个经常被提及但容易被忽视的基础概念。它不仅仅是for循环背后的默默支撑,更是编写高效、节省内存程序的关键工具。简单来说,迭代器是遵循迭代协议的对象,能够一次返回其中的一个元素,而不是一次性把所有数据加载到内存里。

迭代器的基本定义与核心方法
从技术角度看,一个对象只要实现了__iter__()和__next__()两个方法,就可以被称为迭代器。其中__iter__()返回迭代器自身,而__next__()负责返回下一个元素,当没有更多元素时抛出StopIteration异常,从而终止遍历。
与之相关的还有一个概念叫可迭代对象(iterable),比如列表、元组、字符串。它们只实现了__iter__()方法,调用后会返回一个迭代器。很多初学者容易混淆这两者,其实只要记住:能用for循环的都是可迭代对象,但只有能不断调用__next__()取出值的才是迭代器。
下面是一段自定义迭代器的示例代码,它实现了一个从指定数字开始递增的计数器:
class CountUp:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
# 返回迭代器自身
return self
def __next__(self):
if self.current > self.end:
raise StopIteration
num = self.current
self.current += 1
return num
# 使用自定义迭代器
counter = CountUp(1, 3)
it = iter(counter)
print(next(it)) # 输出 1
print(next(it)) # 输出 2
print(next(it)) # 输出 3
迭代器在内存优化上的实际作用
迭代器最大的用处之一,就是处理海量数据或未知长度的数据流时避免内存溢出。假设你有一个十几GB的日志文件,如果直接用readlines()读进列表,程序很可能崩溃;而用文件对象自带的迭代器特性,则能一行一行读取,内存占用始终很低。
再看一个对比示例。下面代码分别用列表和迭代器生成大量数据,前者会立即占用大量空间,后者只有在遍历时才计算:
# 列表推导式:立即生成一百万个整数,占用内存
big_list = [x * 2 for x in range(1000000)]
# 迭代器方式:用map返回迭代器,不立即计算
big_iter = map(lambda x: x * 2, range(1000000))
# 只有真正取用时才计算,节省内存
for val in big_iter:
if val > 10:
break
这种惰性计算(lazy evaluation)特性,使迭代器成为数据管道处理的基石。你可以把多个迭代器操作串起来,比如先用filter过滤,再用map转换,整个过程不产生中间大列表。
迭代器如何简化自定义遍历逻辑
除了省内存,迭代器还能让你灵活控制遍历规则。比如你想从后往前读文件,或者只取偶数行,只需封装一个迭代器类,在__next__()里写自己的逻辑即可,调用方完全不用关心内部细节。
以下示例展示了一个跳行读取文件的迭代器,每次只返回奇数行内容:
class SkipReader:
def __init__(self, filepath):
self.f = open(filepath, 'r', encoding='utf-8')
self.line_no = 0
def __iter__(self):
return self
def __next__(self):
while True:
line = self.f.readline()
if not line:
self.f.close()
raise StopIteration
self.line_no += 1
if self.line_no % 2 == 1:
return line.strip()
# 假设有 test.txt 文件
# reader = SkipReader('test.txt')
# for row in reader:
# print(row)
这样的设计把复杂的读取规则隐藏起来,对外只暴露简单的for循环接口,符合Pythonic的简洁风格。同时,因为迭代器是有状态的,每次遍历完就需要重新创建,这也提醒我们在使用中注意不要重复使用同一个耗尽了的迭代器。
迭代器与生成器、协程的关系
很多高级特性都构建在迭代器之上。生成器(generator)其实就是一种更方便的迭代器写法,用yield关键字自动实现了__iter__和__next__。你不用手动写类,就能得到惰性序列。
示例:用生成器函数改写前面的计数器,代码量明显减少:
def count_up(start, end):
current = start
while current <= end:
yield current
current += 1
for n in count_up(1, 3):
print(n)
在异步编程中,迭代器思想也延伸出了异步迭代器(__aiter__和__anext__),用于处理流式IO。理解最基础的同步迭代器,是掌握这些进阶工具的前提。如果没有迭代器模型,Python的for循环、推导式、生成器表达式都将失去底层支撑。
常见使用误区与注意点
一个典型误区是把迭代器当成列表来多次使用。因为迭代器是一次性消耗的,遍历一次后就会耗尽,再次循环得不到任何数据。如果需要多次使用,应该转为列表,或者重新调用iter()生成新迭代器。
另一个问题是异常处理。手动调用next()时要捕获StopIteration,否则程序会报错;而在for循环里这个异常由语言机制自动处理,所以日常开发优先用for而不是手写next调用。合理利用内置函数如iter、next、enumerate配合自定义迭代器,才能让代码既高效又稳健。