第 10 章 迭代器、生成器与函数式工具

10.1 可迭代对象与迭代器

可迭代对象(Iterable):实现了 __iter__ 的对象——list、str、dict、set、文件等,能用 for 遍历。

迭代器(Iterator):实现了 __iter__ 和 __next__ 的对象,是"一次性的取值流":

nums = [1, 2, 3]
it = iter(nums)        # 从可迭代对象获得迭代器
next(it)               # 1
next(it)               # 2
next(it)               # 3
next(it)               # StopIteration 异常 —— for 循环就是靠它结束的

关键区别:

  • 可迭代对象可以反复遍历;迭代器耗尽即止;

  • for x in obj 内部做了:iter(obj) → 反复 next() → 捕获 StopIteration 结束;

  • zip、enumerate、map、filter、文件对象都返回迭代器——只能消费一次:

z = zip([1, 2], ["a", "b"])
list(z)    # [(1, 'a'), (2, 'b')]
list(z)    # [] !已经耗尽

10.2 生成器:惰性求值的利器

生成器是"自动实现了迭代器协议"的函数——含 yield 关键字的函数:

def countdown(n):
    while n > 0:
        yield n        # 暂停并交出一个值,下次 next 从这里继续
        n -= 1

gen = countdown(3)
next(gen)    # 3
next(gen)    # 2
for x in countdown(3):   # 也可直接 for
    print(x)             # 3 2 1

执行流程:调用生成器函数不执行函数体,返回生成器对象;每次 next() 执行到下一个 yield 暂停;return(或函数结束)触发 StopIteration。

为什么用生成器:内存

# 一次性造出 1000 万个平方数 → 占用数百 MB
squares = [x * x for x in range(10_000_000)]

# 惰性:逐个产出,内存 O(1)
squares = (x * x for x in range(10_000_000))   # 生成器表达式
sum(squares)                                   # 消费时才算

经典管道模式——多个生成器串成数据流水线:

def read_lines(path):
    with open(path, encoding="utf-8") as f:
        yield from f          # yield from:委托给另一个可迭代对象

def filter_errors(lines):
    for line in lines:
        if "ERROR" in line:
            yield line

def parse(line):
    return line.strip()[:80]

pipeline = (parse(l) for l in filter_errors(read_lines("huge.log")))
for item in pipeline:
    print(item)    # 全程内存占用极小

生成器的双向通信(了解)

def echo():
    received = yield "ready"
    while True:
        received = yield f"got: {received}"

g = echo()
next(g)              # 'ready'(先推进到第一个 yield)
g.send("hi")         # 'got: hi'

yield from(委托)、throw()、close() 是进阶话题,初学掌握 yield 与生成器表达式即可。

10.3 函数式工具速览

map filter sorted 的 key

nums = [3, 1, 4, 1, 5, 9, 2, 6]
list(map(str, nums))                    # ['3','1',...]
list(filter(lambda x: x > 3, nums))     # [4, 5, 9, 6]
sorted(nums, key=lambda x: -x)          # 自定义排序键

functools 常用件

import functools

# @cache:记忆化,斐波那契从指数级变线性
@functools.cache
def fib(n):
    return n if n < 2 else fib(n - 1) + fib(n - 2)

# partial:固定部分参数,派生新函数
int2 = functools.partial(int, base=2)
int2("1010")     # 10

# reduce:折叠(多数场景 sum/推导式更清晰,按需使用)
functools.reduce(lambda a, b: a * b, [1, 2, 3, 4])   # 24

itertools 精选

import itertools
list(itertools.chain([1, 2], [3, 4]))          # [1,2,3,4] 拼接
list(itertools.product("AB", "12"))            # 笛卡尔积
list(itertools.combinations([1,2,3], 2))       # 组合 (1,2)(1,3)(2,3)
list(itertools.permutations([1,2], 2))         # 排列 (1,2)(2,1)
list(itertools.groupby(sorted(ws), key=len))   # 分组(先按 key 排序!)
list(itertools.islice(itertools.count(), 3))   # 给无限迭代器截断 [0,1,2]

10.4 闭包与作用域回顾

闭包 = 内层函数记住外层函数的变量:

def make_multiplier(k):
    def multiply(x):
        return x * k      # 记住 k
    return multiply

double = make_multiplier(2)
triple = make_multiplier(3)
double(5)   # 10
triple(5)   # 15

闭包是装饰器、回调、延迟计算的基础(__closure__ 属性可查看捕获的变量)。

10.5 本章小结

  • for 的本质是 iter() + next() + StopIteration;

  • 迭代器一次性耗尽,zip/map/文件对象 的返回值别二次消费;

  • 含 yield 的函数是生成器:惰性、省内存、可搭管道;

  • functools.cache 先于手写缓存;itertools 组合数学问题先查它;

  • 闭包记住外层变量,是装饰器的原理。


至此 Python 基础篇完结。进阶方向:并发(threading asyncio)、网络编程(requests socket)、测试(pytest)、Web 框架(FastAPI Flask)与数据分析(pandas NumPy)。

Python3 基础知识 / 第 10 章 迭代器、生成器与函数式工具 0 字 0 行 cosolar
2026-09-17T11:10:47.779240644Z 2026-09-17T11:25:55.311718301Z