Python学习之路-Python3 迭代器与生成器学习详解

独行者无惧黑暗,因为他的影子,就是最锋利的剑。

学习打卡第十八天

迭代和生成是 Python 中处理序列数据的核心机制,迭代器与生成器不仅能让代码更高效,还能帮理解 Python 底层的迭代逻辑。

一、迭代器

遍历集合的高效工具

1.迭代器解释

迭代器是一个可以记住遍历位置 的对象,它从集合的第一个元素开始访问,直到所有元素被访问完结束,且只能向前遍历,不能后退

核心特征是:

  • 可通过 iter() 函数创建
  • 可通过 next() 函数获取下一个元素
  • 遍历结束时会触发 StopIteration 异常

2.迭代器的基本使用

(1)创建迭代器

字符串、列表、元组等可迭代对象都能通过 iter() 函数创建迭代器:

python 复制代码
# 列表创建迭代器示例
list_data = [1, 2, 3, 4]
it = iter(list_data)  # 创建迭代器对象

# 用 next() 获取元素
print(next(it))  # 输出:1
print(next(it))  # 输出:2

(2)遍历迭代器

迭代器可直接用 for 循环遍历,无需手动处理 StopIteration 异常:

python 复制代码
list_data = [1, 2, 3, 4]
it = iter(list_data)
for x in it:
    print(x, end=" ")  # 输出:1 2 3 4

也可通过 while 循环配合 try-except 捕获异常:

python 复制代码
import sys
list_data = [1, 2, 3, 4]
it = iter(list_data)

while True:
    try:
        print(next(it))  # 逐个获取元素
    except StopIteration:
        sys.exit()  # 遍历结束时退出

3. 自定义迭代器

通过类实现迭代器需重写两个方法:

  • __iter__():返回迭代器对象本身(通常返回 self
  • __next__():返回下一个元素,遍历结束时触发 StopIteration

示例:创建一个递增数字迭代器

python 复制代码
class MyNumbers:
    def __iter__(self):
        self.a = 1  # 初始值
        return self

    def __next__(self):
        if self.a <= 10:  # 限制迭代次数
            x = self.a
            self.a += 1
            return x
        else:
            raise StopIteration  # 触发停止异常


# 使用自定义迭代器
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
    print(x)  # 输出 1 到 10

二、生成器

简化迭代器的创建

1.生成器解释

生成器是一种特殊的迭代器 ,通过 yield 关键字定义的函数创建。它无需手动实现 __iter__()__next__() 方法,就能实现迭代功能。

生成器的核心特点:

  • 调用生成器函数返回的是迭代器对象
  • 通过 yield 语句暂停执行并返回值
  • 再次调用时从上次暂停的位置继续执行

2. 生成器的基本使用

(1)简单生成器示例

python 复制代码
def countdown(n):
    while n > 0:
        yield n  # 暂停并返回当前值
        n -= 1

# 创建生成器对象
generator = countdown(5)

# 逐步获取值
print(next(generator))  # 输出:5
print(next(generator))  # 输出:4

# 用 for 循环遍历剩余值
for value in generator:
    print(value)  # 输出:3 2 1

3. 生成器的优势

  • 内存高效:无需一次性生成所有数据,按需产生值,适合处理大量数据
  • 代码简洁:比自定义迭代器少写大量模板代码
  • 无缝集成 :可直接用于 for 循环、列表推导等迭代场景

三、迭代器与生成器的区别

特性 迭代器 生成器
计算方式 立即计算所有元素 按需生成,延迟计算
内存占用 存储全部元素 仅保存当前状态
遍历限制 可双向遍历(部分实现) 单向遍历,状态不可逆

四、实战应用

案例:大文件逐行处理

  • 问题‌:传统读取大文件易导致内存溢出。

解决方案

python 复制代码
def read_large_file(file_path):
    with open(file_path, 'r') as f:
        # 文件对象为迭代器
        for line in f:
            # 逐行生成,节省内存
            yield line.strip() 

优势‌:避免一次性加载全部内容,适用于日志分析等场景。

案例:实时数据流模拟

  • 问题‌:需要持续产出动态数据。

解决方案

python 复制代码
import asyncio
import random
async def stock_price_generator(symbol):
    price = 100.0
    while True:
        await asyncio.sleep(0.5)
        price += random.uniform(-1, 1)
        # 异步生成器示例
        yield price
async def main():
    generator = stock_price_generator("AAPL")
    async for price in generator:
        print(f"Current price: {price:.2f}")
        if price > 110 or price < 90:
            print("Price out of range!")
            break

if __name__ == "__main__":
    asyncio.run(main())

代码说明:

  1. 该代码实现了一个异步生成器函数 stock_price_generator,用于模拟股票价格的实时变化。

  2. 使用 asyncio.sleep 控制生成频率,每次生成间隔 0.5 秒。

  3. 通过 random.uniform 生成随机波动,使价格在一定范围内变动。

  4. 主函数中使用 async for 循环消费生成的价格数据,并在价格超出设定范围时停止。

**案例:**编写一个生成器函数,生成斐波那契数列前10项。

python 复制代码
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib_gen = fibonacci()
for i in range(10):
    print(next(fib_gen))

**案例:**使用生成器表达式过滤100以内所有3的倍数的平方数。

python 复制代码
# 使用生成器表达式过滤100以内所有3的倍数的平方数
result = (x**2 for x in range(1, 101) if x % 3 == 0)

# 打印结果
print("100以内所有3的倍数的平方数:")
for num in result:
    print(num, end=' ')
print()  # 换行

代码说明:

  1. 该代码展示了生成器表达式与列表推导式的区别。

  2. 生成器表达式使用圆括号(),而列表推导式使用方括号[]。

  3. 生成器表达式是惰性求值,节省内存空间。

  4. 列表推导式会立即计算所有结果,占用更多内存。

案例:实现一个生成器类,模拟时间戳序列(格式:YYYY-MM-DD HH:MM:SS),起始时间为当前时间。

python 复制代码
import datetime
import time


class TimestampGenerator:
    """时间戳生成器类,模拟时间戳序列"""

    def __init__(self, start_time=None):
        """
        初始化时间戳生成器
        :param start_time: 起始时间,默认为当前时间
        """
        if start_time is None:
            self.current_time = datetime.datetime.now()
        else:
            self.current_time = start_time

    def __iter__(self):
        """返回迭代器对象本身"""
        return self

    def __next__(self):
        """返回下一个时间戳"""
        timestamp = self.current_time.strftime("%Y-%m-%d %H:%M:%S")
        self.current_time += datetime.timedelta(seconds=1)
        return timestamp

    def next_n(self, n):
        """
        获取接下来的n个时间戳
        :param n: 数量
        :return: 时间戳列表
        """
        return [next(self) for _ in range(n)]


def main():
    """主函数演示时间戳生成器的使用"""
    print("时间戳生成器演示:")
    print("=" * 40)

    # 创建时间戳生成器实例
    generator = TimestampGenerator()

    # 生成前10个时间戳
    print("前10个时间戳序列:")
    for i, timestamp in enumerate(generator):
        print(f"{i + 1:2d}. {timestamp}")
        if i >= 9:
            break

    print("\n" + "=" * 40)

    # 使用next_n方法获取接下来的5个时间戳
    print("接下来的5个时间戳:")
    next_timestamps = generator.next_n(5)
    for i, ts in enumerate(next_timestamps, 1):
        print(f"{i:2d}. {ts}")


if __name__ == "__main__":
    main()

五、总结

  • 核心回顾 ‌:
    迭代器是基础协议,生成器通过yield实现惰性计算,适用于大数据、实时流等场景。
  • 常见误区 ‌:
    • 生成器无法随机访问元素,需从头遍历。
    • 生成器耗尽后需重新创建,避免重复使用。
  • 拓展方向 ‌:
    结合装饰器优化生成器性能,或探索异步生成器在并发编程中的应用。
相关推荐
云小逸2 小时前
【Nmap 源码学习】深度解析:main.cc 入口函数详解
网络·windows·学习·nmap
醇氧2 小时前
【Linux】centos 防火墙学习
linux·学习·centos
xqqxqxxq2 小时前
洛谷算法1-3 暴力枚举(NOIP经典真题解析)java(持续更新)
java·开发语言·算法
Free Tester2 小时前
UI自动化测试中的Mixin设计模式
python·自动化
爱上妖精的尾巴2 小时前
8-5 WPS JS宏 match、search、replace、split支持正则表达式的字符串函数
开发语言·前端·javascript·wps·jsa
阿猿收手吧!2 小时前
【C++】inline变量:全局共享新利器
开发语言·c++
沐知全栈开发2 小时前
Python3 列表详解
开发语言
~光~~2 小时前
【嵌入式linux学习】06_中断子系统
linux·单片机·学习
蒸蒸yyyyzwd2 小时前
DDIA学习笔记
笔记·学习