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
方法 返回值 调用时机
__iter__ 迭代器对象本身 for循环或iter()调用时
__next__ 下一个元素或StopIteration 每次获取下一个元素时

三、斐波那契迭代器实战

斐波那契数列是一个经典的无限序列,每个数都是前两个数之和。使用自定义迭代器可以优雅地实现它,并且可以按需生成任意数量的项,而不需要预先存储所有值。

代码示例

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就是一种实现方式。

标签: 自定义迭代器 斐波那契 惰性求值 __iter__ StopIteration

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python迭代协议详解 - __iter__与__next__完全指南 下一篇: Python生成器函数yield - 惰性求值与高效编程指南

poll相关推荐