pin_drop当前位置:知识文库 ❯ 图文
Python自定义迭代器 - 实现迭代器类与斐波那契数列
一、为什么需要自定义迭代器
Python内置的迭代器虽然强大,但在某些场景下无法满足需求。例如:需要按特定规则生成数据序列、需要按需加载大量数据、或者需要实现复杂的遍历逻辑时,自定义迭代器就成了最佳选择。
自定义迭代器最大的优势是惰性求值——只有在需要时才计算下一个值,这可以显著节省内存,特别适合处理大数据集或无限序列。
二、实现迭代器的基本要求
在Python中,一个类要成为迭代器,必须实现两个魔术方法:
-
__iter__:返回迭代器对象本身(通常是return self)
-
__next__:返回下一个元素,没有元素时抛出StopIteration异常
代码示例
class Counter:
"""最简单的自定义迭代器:从start计数到end"""
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
value = self.current
self.current += 1
return value
# 使用示例
counter = Counter(1, 5)
for num in counter:
print(num) # 输出: 1 2 3 4 5三、斐波那契迭代器实战
斐波那契数列是一个经典的无限序列,每个数都是前两个数之和。使用自定义迭代器可以优雅地实现它,并且可以按需生成任意数量的项,而不需要预先存储所有值。
代码示例
class Fibonacci:
"""斐波那契数列迭代器,可限制生成的数量"""
def __init__(self, max_count=None):
self.max_count = max_count # None表示无限生成
self.count = 0
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
if self.max_count is not None and self.count >= self.max_count:
raise StopIteration
self.count += 1
value = self.a
self.a, self.b = self.b, self.a + self.b
return value
# 生成前10个斐波那契数
fib = Fibonacci(max_count=10)
for num in fib:
print(num, end=" ")
# 输出: 0 1 1 2 3 5 8 13 21 34
# 使用itertools配合无限迭代器
from itertools import islice
fib_infinite = Fibonacci() # 无限生成
first_five = list(islice(fib_infinite, 5))
print(f"\n前5个: {first_five}") # 前5个: [0, 1, 1, 2, 3]四、代码示例与进阶用法
示例1:反向迭代器
代码示例
class ReverseIterator:
"""反向遍历序列的迭代器"""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index -= 1
return self.data[self.index]
# 使用示例
words = ["Python", "Java", "C++", "Go"]
for word in ReverseIterator(words):
print(word)
# 输出: Go C++ Java Python示例2:文件行读取迭代器
代码示例
class FileLineIterator:
"""逐行读取文件的迭代器,自动去除空白行"""
def __init__(self, filepath):
self.file = open(filepath, "r", encoding="utf-8")
def __iter__(self):
return self
def __next__(self):
while True:
line = self.file.readline()
if not line: # 文件结束
self.file.close()
raise StopIteration
line = line.strip()
if line: # 跳过空白行
return line
def __del__(self):
"""确保文件被正确关闭"""
if hasattr(self, 'file') and not self.file.closed:
self.file.close()
# 使用示例(假设有test.txt文件)
# for line in FileLineIterator("test.txt"):
# print(line)示例3:可重置的迭代器
代码示例
class ResettableRange:
"""支持重置的迭代器"""
def __init__(self, start, end):
self.start = start
self.end = end
self.reset()
def reset(self):
self.current = self.start
def __iter__(self):
self.reset() # 每次迭代都从头开始
return self
def __next__(self):
if self.current > self.end:
raise StopIteration
value = self.current
self.current += 1
return value
# 使用示例
rng = ResettableRange(1, 3)
print(list(rng)) # [1, 2, 3]
print(list(rng)) # [1, 2, 3] - 可以重复遍历!五、注意事项与最佳实践
注意1:迭代器的__iter__方法必须返回self。如果返回其他对象,会导致for循环行为异常,因为for循环期望迭代器的__iter__返回迭代器本身。
注意2:如果迭代器持有外部资源(如文件、网络连接),务必实现__del__或使用上下文管理器确保资源被正确释放,避免资源泄漏。
注意3:不要在迭代过程中修改被迭代的数据结构,这会导致不可预测的行为。如果需要修改,先创建副本或使用生成器。
小贴士
对于简单的迭代器,优先考虑使用生成器函数(yield),代码更简洁。自定义迭代器类更适合需要保存复杂状态、或需要额外方法(如reset、peek等)的场景。
六、练习题
练习1
实现一个自定义迭代器EvenNumbers(n),生成前n个偶数(从2开始)。使用for循环遍历并打印结果。
练习2
实现一个SlideWindow迭代器,接受一个列表和窗口大小,逐个返回滑动窗口的元素。例如:SlideWindow([1,2,3,4,5], 3) 依次返回 [1,2,3], [2,3,4], [3,4,5]。
常见问题
自定义迭代器和生成器应该选择哪个?
对于简单场景,生成器更简洁(只需一个yield函数)。当需要复杂状态管理、多个方法、或面向对象的设计时,自定义迭代器类更合适。两者底层原理相同,选择取决于代码复杂度。
为什么__iter__要返回self?
因为for循环的工作流程是:先调用__iter__获取迭代器,然后不断调用迭代器的__next__。如果__iter__不返回self,for循环会对返回值再次调用__iter__,可能导致无限循环或意外行为。
如何实现可以多次遍历的迭代器?
在__iter__方法中重置迭代状态(如重置索引),或者将迭代逻辑分离到独立的迭代器类中。示例3中的ResettableRange就是一种实现方式。
本文涉及AI创作
内容由AI创作,请仔细甄别