一、三器一闭总览

"三器一闭"是Python中四个核心高级特性:

  • 闭包:函数 + 环境,是装饰器的基础
  • 装饰器:基于闭包的进阶应用
  • 迭代器:实现了 __iter____next__ 方法的对象
  • 生成器:特殊的迭代器,使用 yield 关键字

它们的关系:
闭包 → 装饰器(基于闭包)
迭代器 → 生成器(特殊迭代器)

二、什么是迭代器

迭代器是一种设计模式,能够顺序访问集合中的元素,无需暴露集合的内部结构。通俗理解:迭代器是一个"指哪打哪"的智能指针,你只需要告诉它"给我下一个元素",它就会按顺序返回。

核心协议

  • __iter__():返回迭代器对象本身
  • __next__():返回下一个元素,没有更多元素时抛出 StopIteration 异常

三、创建迭代器的三种方式

方法1:使用 iter() 函数

# 将可迭代对象转换为迭代器
list1 = [1, 2, 3, 4, 5]
iter1 = iter(list1)

# 用 next() 逐个获取元素
print(next(iter1))  # 1
print(next(iter1))  # 2
print(next(iter1))  # 3
# 元素取完后抛出 StopIteration 异常

方法2:for循环遍历迭代器

for循环本质上就是不断调用 next(),直到捕获 StopIteration 异常后自动停止:

list1 = [1, 2, 3, 4, 5]
iter1 = iter(list1)

for i in iter1:
    print(i)  # 1 2 3 4 5

方法3:自定义迭代器类

需要定义一个类,实现 __iter__()__next__() 方法:

class MyIter:
    def __init__(self):
        self.a = 1  # 初始化计数器

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

    def __next__(self):
        if self.a <= 5:  # 设置停止条件
            x = self.a
            self.a += 1
            return x
        else:
            raise StopIteration  # 抛出异常,结束迭代

# 使用自定义迭代器
myiter = MyIter()
for i in myiter:
    print(i)  # 1 2 3 4 5

四、可迭代对象 vs 迭代器

重要区别

  • 可迭代对象:实现了 __iter__() 方法的对象(如列表、元组、字典)
  • 迭代器:实现了 __iter__()__next__() 方法的对象
# 可迭代对象(但不是迭代器)
class MyIterable:
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return iter(self.data)  # 返回一个新的迭代器

# 迭代器(同时实现了 __iter__ 和 __next__)
class MyIterator:
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return self

    def __next__(self):
        if self.data <= 0:
            raise StopIteration
        else:
            value = self.data
            self.data -= 1
            return value

for num in MyIterator(5):
    print(num)  # 5 4 3 2 1

一句话区分:所有的迭代器都是可迭代对象,但并非所有可迭代对象都是迭代器。列表是可迭代对象但不是迭代器,iter(列表) 返回的才是迭代器。

五、内置迭代工具

iter() 和 next() 函数

list1 = [1, 2, 3, 4, 5]
iter1 = iter(list1)
print(next(iter1))  # 1
print(next(iter1))  # 2

itertools 模块(提供更多迭代工具):

import itertools

# 无限计数迭代器
for i in itertools.count(10):
    print(i)  # 10, 11, 12, ... 无限循环

# 循环迭代器
for i in itertools.cycle([1, 2, 3]):
    print(i)  # 1, 2, 3, 1, 2, 3, ... 无限循环

六、迭代器的优势

  1. 惰性计算:只在需要时生成值,节省内存
  2. 无限序列:可以表示无限序列(如自然数序列)
  3. 统一接口:为不同的数据结构提供统一的遍历接口
  4. 状态保持:自动记住遍历位置

七、生成器

生成器是简化版的迭代器,用 yield 关键字替代 return,Python会自动为其生成 __iter__()__next__() 方法。

核心特征

  • 执行到 yield 时暂停,保留当前状态
  • 下次调用 next() 时从暂停处继续执行
  • 执行完毕后自动抛出 StopIteration 异常

普通函数 vs 生成器函数

# 普通函数:一次性返回所有数据
def run():
    return [1, 2, 3, 4, 5]

result = run()  # 返回完整列表 [1, 2, 3, 4, 5]

# 生成器函数:逐个返回数据
def run2():
    yield 1
    yield 2
    yield 3
    yield 4
    yield 5

gen = run2()       # 返回生成器对象
print(next(gen))   # 1
print(next(gen))   # 2

八、创建生成器的三种方法

方法1:生成器函数(最常用)

使用 yield 关键字的函数:

def count_up_to(n):
    """生成从1到n的数字"""
    count = 1
    while count <= n:
        yield count
        count += 1

counter = count_up_to(5)
print(list(counter))  # [1, 2, 3, 4, 5]

# 直接遍历
for num in count_up_to(5):
    print(num)  # 1 2 3 4 5

方法2:生成器表达式

类似列表推导式,但使用圆括号:

nums = (x * x for x in range(5))
print(nums)         # 生成器对象
print(list(nums))   # [0, 1, 4, 9, 16]

方法3:使用 yield from(Python 3.3+)

从另一个可迭代对象中生成值:

def count_up_to(n):
    yield from range(n)  # 从range中逐个生成值

print(list(count_up_to(5)))  # [0, 1, 2, 3, 4]

九、生成器的工作原理

状态保持:生成器函数在 yield 处暂停执行,并保存所有局部变量状态:

def get_name(n):
    for i in range(n):
        yield "张三" + str(i)

gen = get_name(5)
print(next(gen))  # 张三0(暂停在yield处)
print(next(gen))  # 张三1(从上次暂停处继续)
print(next(gen))  # 张三2

send() 方法:向生成器发送值:

def my_iter(n):
    for i in range(n):
        name = yield "张三" + str(i)
        print("接收到的值:", name)

gen = my_iter(5)
print(next(gen))      # 张三0(启动生成器)
print(gen.send(10))   # 接收到的值: 10 → 张三1
gen.close()           # 关闭生成器

throw() 和 close() 方法

  • throw():向生成器内部抛出异常
  • close():关闭生成器,后续调用 next() 会抛出 StopIteration

十、生成器的实战场景

场景1:逐行读取大型文件(节省内存)

def read_file(filename):
    with open(filename, "r", encoding="utf-8") as f:
        for line in f:
            yield line.strip()  # 逐行返回

# 使用生成器读取文件
lines = read_file("jk.txt")
for line in lines:
    print(line)

场景2:生成无限序列(无需担心内存溢出)

def infinite_counter(start):
    while True:
        yield start
        start += 1

num = infinite_counter(1)
for _ in range(5):
    print(next(num))  # 1, 2, 3, 4, 5

十一、生成器 vs 普通迭代器

特性 普通迭代器(自定义类) 生成器
实现方式 手动写 __iter__ + __next__ yield 关键字,自动生成
代码量 多(需定义类、处理状态) 少(函数/表达式即可)
状态管理 手动维护(如index变量) 自动维护(Python保存执行状态)
开发效率 高(极简写法)
功能 灵活(可自定义复杂逻辑) 简洁(适合常规迭代场景)

一句话总结:生成器 = 迭代器的"懒人写法",用最少的代码实现迭代器的核心功能。

今日核心总结

  1. 迭代器

    • 实现了 __iter__()__next__() 方法的对象
    • iter() 将可迭代对象转为迭代器
    • next() 逐个获取元素,取完抛出 StopIteration
    • 惰性计算,节省内存,自动记住遍历位置
  2. 可迭代对象 vs 迭代器

    • 可迭代对象:有 __iter__()(如列表、字典)
    • 迭代器:有 __iter__()__next__()(如 iter(list)
    • 所有迭代器都是可迭代对象,反之不一定
  3. 生成器

    • 简化版迭代器,用 yield 关键字
    • 三种创建方式:生成器函数、生成器表达式、yield from
    • 状态自动保存,执行到 yield 暂停,下次 next() 继续
    • 适合处理大数据、超大文件、无限序列
  4. 三器一闭关系

    • 闭包是装饰器的基础
    • 生成器是迭代器的简化版
    • 生成器表达式是列表推导式的惰性版本

注:已经使用DeepSeek进行整理精简核心内容,些许不理解的配合个人笔记进行理解。

更多推荐