Python 迭代器与生成器专项练习:6 道编程题从入门到精通

配套专栏Python 全栈修炼之路 第 13 篇《迭代器与生成器——惰性求值的艺术》

难度分布:⭐ → ⭐⭐ → ⭐⭐ → ⭐⭐⭐ → ⭐⭐⭐ → ⭐⭐⭐⭐

核心覆盖__iter__/__next__yield、生成器表达式、itertoolsyield from、协程通信


前言

第十三篇是进阶修炼篇的开篇,核心主题是惰性求值——用最少的内存处理最多的数据。本练习精选 6 道编程题,从自定义迭代器到协程管道,层层递进,帮你彻底掌握迭代器与生成器的精髓。


题目一:自定义迭代器——倒计时与步进器 ⭐

📌 题目描述

实现两个自定义迭代器类,手动实现 __iter____next__ 协议:

# 倒计时迭代器
cd = CountDown(5)
print(list(cd))  # [5, 4, 3, 2, 1]

# 步进迭代器(支持任意步长和方向)
step = Stepper(0, 10, 2)
print(list(step))  # [0, 2, 4, 6, 8, 10]

step2 = Stepper(10, 0, -3)
print(list(step2))  # [10, 7, 4, 1]

# 迭代器只能遍历一次
cd2 = CountDown(3)
print(list(cd2))  # [3, 2, 1]
print(list(cd2))  # [](已耗尽)

💡 编程思路

这道题考察 迭代器协议__iter__ 返回 self__next__ 产生下一个值或抛出 StopIteration

  1. CountDown:内部维护一个计数器 self.current,每次 __next__ 返回当前值并递减,到 0 时抛出 StopIteration
  2. Stepper:支持 startstopstep 三个参数,类似 range() 但作为类实现。需要处理正步长和负步长两种情况。
  3. 一次性特性:迭代器耗尽后再次遍历返回空列表,这是迭代器与可迭代对象的核心区别。

🖥️ 参考代码

from collections.abc import Iterator


class CountDown:
    """倒计时迭代器:从 start 倒数到 1。"""

    def __init__(self, start: int):
        if start < 0:
            raise ValueError("start 必须为非负整数")
        self.current = start

    def __iter__(self) -> "CountDown":
        return self

    def __next__(self) -> int:
        if self.current <= 0:
            raise StopIteration
        value = self.current
        self.current -= 1
        return value

    def __repr__(self) -> str:
        return f"CountDown({
     
     self.current})"


class Stepper:
    """步进迭代器:类似 range(),但以迭代器协议实现。"""

    def __init__(self, start: int, stop: int, step: int = 1):
        if step == 0:
            raise ValueError("step 不能为 0")
        self.start = start
        self.stop = stop
        self.step = step
        self.current = start
        self._exhausted = False

    def __iter__(self) -> "Stepper":
        return self

    def __next__(self) -> int:
        if self._exhausted:
            raise StopIteration

        if self.step > 0 and self.current > self.stop:
            self._exhausted = True
            raise StopIteration
        if self.step < 0 and self.current < self.stop:
            self._exhausted = True
            raise StopIteration

        value = self.current
        self.current += self.step
        return value

    def __repr__(self) -> str:
        return f"Stepper({
     
     self.start}, {
     
     self.stop}, {
     
     self.step})"


class Repeater:
    """重复元素迭代器:无限重复指定元素 n 次。"""

    def __init__(self, value, times: int):
        self.value = value
        self.times = times
        self.count = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.count >= self.times:
            raise StopIteration
        self.count += 1
        return self.value


# 测试
if __name__ == "__main__":
    print("=== CountDown ===")
    cd = CountDown(5)
    print(f"类型: {
     
     type(cd)}")
    print(f"是迭代器: {
     
     isinstance(cd, Iterator)}")
    print(f"遍历: {
     
     list(cd)}")
    print(f"再次遍历: {
     
     list(cd)}  # 已耗尽")

    print("\n=== Stepper ===")
    print(f"正步长: {
     
     list(Stepper(0, 10, 2))}")
    print(f"负步长: {
     
     list(Stepper(10, 0, -3))}")
    print(f"单元素: {
     
     list(Stepper(5, 5, 1))}")

    print("\n=== Repeater ===")
    print(f"重复 5 次: {
     
     list(Repeater('Hello', 5))}")

    print("\n=== for 循环兼容 ===")
    for i in CountDown(3):
        print(f"  倒计时: {
     
     i}")

    print("\n所有测试通过 ✓")

🔗 关联知识点

知识点 说明
__iter__ 返回迭代器自身
__next__ 返回下一个值或 StopIteration
迭代器一次性 耗尽后不可复用
isinstance(obj, Iterator) 迭代器类型检查
for 循环原理 自动调用 iter()next()

题目二:生成器函数——斐波那契与素数 ⭐⭐

📌 题目描述

使用 yield 实现两个经典数学序列生成器:

# 斐波那契数列(前 N 个)
fibs = list(fibonacci(10))
print(fibs)  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

# 无限斐波那契 + islice 截取
from itertools import islice
print(list(islice(fibonacci_infinite(), 8)))  # [0, 1, 1, 2, 3, 5, 8, 13]

# 素数生成器(前 N 个)
primes = list(prime_generator(10))
print(primes)  # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

# 无限素数 + takewhile 截取
from itertools import takewhile
print(list(takewhile(lambda x: x < 50, prime_infinite())))  # [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]

# 内存对比
import sys
fib_list = [fibonacci(100000)]  # 大量内存
fib_gen = fibonacci(100000)      # 几乎不占内存
print(f"列表: {
     
     sys.getsizeof(list(fibonacci(1000)))} bytes")
print(f"生成器: {
     
     sys.getsizeof(fibonacci(1000))} bytes")

💡 编程思路

这道题考察 yield 惰性求值 + 无限序列 + itertools 截取

  1. 有限斐波那契yield 每次产生一个数,用 count 控制数量。
  2. 无限斐波那契while True + yield,永不停止,配合 islice 截取。
  3. 素数生成器:维护一个素数列表,用试除法判断新数是否为素数。
  4. 内存优势:生成器不存储所有值,只在需要时计算,适合大数据量。

🖥️ 参考代码

import sys
import time
from itertools import islice, takewhile


def fibonacci(n: int):
    """生成前 n 个斐波那契数(有限生成器)。"""
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b


def fibonacci_infinite():
    """无限斐波那契数列生成器。"""
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b


def prime_generator(n: int):
    """生成前 n 个素数。"""
    primes = []
    candidate = 2
    while len(primes) < n:
        is_prime = True
        for p in primes:
            if p * p > candidate:
                break
            if candidate % p == 0:
                is_prime = False
                break
        if is_prime:
            primes.append(candidate)
            yield candidate
        candidate += 1


def prime_infinite():
    """无限素数生成器。"""
    primes = []
    candidate = 2
    while True:
        is_prime = True
        for p in primes:
            if p * p > candidate:
                break
            if candidate % p == 0:
                is_prime = False
                break
        if is_prime:
            primes.append(candidate)
            yield candidate
        candidate += 1


def collatz(start: int):
    """考拉兹猜想(冰雹猜想)序列生成器。"""
    n = start
    while n != 1:
        yield n
        if n % 2 == 0:
            n = n // 2
        else:
            n = 3 * n + 1
    yield 1


# 测试
if __name__ == "__main__":
    print("=== 斐波那契(有限) ===")
    print(f"前 10 个: {
     
     list(fibonacci(10))}")
    print(f"前 20 个: {
     
     list(fibonacci(20))}")

    print("\n=== 斐波那契(无限 + islice) ===")
    print(f"第 5~15 个: {
     
     list(islice(fibonacci_infinite(), 5, 15))}")

    print("\n=== 素数生成器 ===")
    print(f"前 10 个素数: {
     
     list(prime_generator(10))}")
    print(f"小于 50 的素数: {
     
     list(takewhile(lambda x: x < 50, prime_infinite()))}")

    print("\n=== 考拉兹序列 ===")
    print(f"start=27: {
     
     list(collatz(27))}")
    print(f"start=6: {
     
     list(collatz(6))}")

    print("\n=== 内存对比 ===")
    n = 1000
    fib_list = list(fibonacci(n))
    fib_gen = fibonacci(n)
    print(f"列表内存: {
     
     sys.getsizeof(fib_list):,} bytes")
    print(f"生成器内存: {
     
     sys.getsizeof(fib_gen)} bytes")
    print(f"内存比: {
     
     sys.getsizeof(fib_list) / sys.getsizeof(fib_gen):.0f}x"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值