Python 进阶 - 第十九节


📋 本节要点

知识点 说明
可迭代对象 可用 for 循环遍历的对象(列表、字符串等)
迭代器 可通过 iter()/next() 逐个取值的对象
生成器 使用 yield 的特殊迭代器,按需生成数据
列表推导式 [] 快速创建列表,立即生成所有数据
生成器表达式 () 按需生成,节省内存

1. 可迭代对象 vs 迭代器

可迭代对象(Iterable)是可以用 for 循环遍历的对象,如 list、tuple、dict、str 等。

迭代器(Iterator)是真正逐个返回数据的对象,通过 iter() 将可迭代对象转为迭代器,用 next() 取值,遍历完抛出 StopIteration。

from collections.abc import Iterable

# 检查是否为可迭代对象
print(isinstance([], Iterable))    # True
print(isinstance("abc", Iterable)) # True
print(isinstance(123, Iterable))   # False(整数不可迭代)

# 迭代器使用
my_list = [1, 2, 3]    # 可迭代对象
it = iter(my_list)       # 获取迭代器

print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# print(next(it))  # StopIteration 异常(已遍历完)

2. 列表推导式

列表推导式(也称列表生成式)用简洁的语法快速创建列表,立即生成所有数据。

# 普通方式创建列表
L = []
for x in range(1, 11):
    L.append(x * x)
print(L)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 列表推导式(一行搞定)
M = [x * x for x in range(1, 11)]
print(M)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 带条件的列表推导式
N = [x * x for x in range(1, 11) if x % 2 == 0]
print(N)  # [4, 16, 36, 64, 100]

3. 生成器

生成器是一种特殊的迭代器,使用 yield 关键字。调用生成器函数不会立即执行,而是返回一个生成器对象,通过 next() 获取值,每次执行到 yield 暂停,下次从暂停处继续。

3.1 生成器表达式

类似列表推导式,但用 () 替代 [],返回生成器对象,按需生成,节省内存。

# 列表推导式(立即生成所有内容)
M = [x * x for x in range(1, 11)]
print(M)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 生成器表达式(按需生成)
O = (x * x for x in range(1, 11))
print(O)  # <generator object ...>

# 用 for 循环遍历生成器
for i in O:
    print(i, end=" ")  # 1 4 9 16 25 36 49 64 81 100

3.2 生成器函数

用 def 定义生成器,内部使用 yield 暂停并返回值。

def my_generator():
    yield 1
    yield 2
    yield 3

# 创建生成器对象
gen = my_generator()

# 用 next() 逐个取值
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
# print(next(gen))  # StopIteration

# 也可以用 for 循环遍历
def my_generator():
    yield 1
    yield 2
    yield 3

for i in my_generator():
    print(i)  # 1 2 3

4. 实战:斐波那契数列

用生成器实现斐波那契数列,每次只生成一个数,按需计算。

def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

# 使用 for 循环遍历
for num in fibonacci(10):
    print(num, end=" ")  # 0 1 1 2 3 5 8 13 21 34

5. 实战:生成器读取大文件

读取大文件时,一次性加载会耗尽内存,生成器一次只读一行:

def read_lines(file_path):
    """逐行读取文件,每次只返回一行"""
    with open(file_path, 'r', encoding='utf-8') as f:
        for line in f:
            yield line.strip()

# 处理超大日志文件,内存占用恒定
for line in read_lines("huge_log.txt"):
    process(line)  # 每次只处理一行

下一节预告:函数式编程