主题:生成器与上下文管理器
目标
- 理解生成器的工作原理与
yield
表达式。 - 初步了解协程的概念与应用。
- 学习如何实现自定义上下文管理器。
- 通过生成器管道处理大文件。
一、生成器与 yield
表达式
1. 生成器的基本概念
生成器是一种特殊的迭代器,能够逐步生成数据,而不是一次性生成并存储所有数据。生成器函数使用 yield
关键字来返回值。
示例:
python
def my_generator():
print("生成器开始执行")
yield 1
print("生成器继续执行")
yield 2
print("生成器结束执行")
# 使用生成器
g = my_generator()
print(next(g)) # 输出:1
print(next(g)) # 输出:2
解释:
- 生成器函数
my_generator
使用yield
返回值。 - 每次调用
next()
时,生成器从上次暂停的位置继续执行。 - 生成器的状态会被保留,直到生成器完成或抛出
StopIteration
。
2. 生成器的优势
- 内存高效:生成器逐个生成数据,适合处理大数据或无限序列。
- 惰性计算:只在需要时生成数据,避免不必要的计算。
示例:处理大文件
python
def read_file(filename):
with open(filename, 'r') as f:
for line in f:
yield line.strip()
# 使用生成器处理大文件
for line in read_file('large_file.txt'):
process(line)
解释:
read_file
是一个生成器函数,逐行读取文件内容。- 这种方式适合处理大文件,避免一次性将所有内容加载到内存。
3. 协程初步
协程(Coroutine)是一种高级的生成器,它不仅可以生成数据,还可以接收数据。协程通常用于实现高效的异步编程。
示例:简单的协程
python
def my_coroutine():
print("协程开始")
x = yield # 接收外部发送的值
print(f"接收到的值:{x}")
print("协程结束")
# 使用协程
c = my_coroutine()
next(c) # 启动协程
c.send(10) # 发送值到协程
输出:
协程开始
接收到的值:10
协程结束
解释:
- 协程使用
yield
语句来接收外部发送的值。 - 需要先调用
next()
启动协程,然后使用send()
发送数据。
二、上下文管理器
1. 上下文管理器的基本概念
上下文管理器用于管理资源的生命周期(如文件、网络连接等),确保资源在使用后正确释放。常见的上下文管理器是 with
语句。
内置上下文管理器示例:
python
with open('file.txt', 'r') as f:
# 文件在代码块结束时自动关闭
content = f.read()
自定义上下文管理器:
实现 __enter__
和 __exit__
方法。
示例:
python
class MyContextManager:
def __enter__(self):
print("进入上下文")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出上下文")
# 处理异常(可选)
if exc_type is not None:
print(f"捕获异常:{exc_type.__name__}")
return True # 返回 True 表示已处理异常
# 使用自定义上下文管理器
with MyContextManager():
print("在上下文中执行代码")
输出:
进入上下文
在上下文中执行代码
退出上下文
2. 上下文管理器的应用场景
- 文件操作:自动关闭文件。
- 锁管理:自动释放锁。
- 数据库连接:自动关闭连接。
三、作业:处理大文件的生成器管道
目标
- 使用生成器构建一个处理大文件的管道。
- 实现数据的分阶段处理,提高效率。
示例场景
假设有一个大文件 large_file.txt
,每行包含一些数据。我们需要对数据进行以下处理:
- 读取文件并去除空白字符。
- 过滤出满足条件的行(如长度大于 10 的行)。
- 对过滤后的行进行转换(如转为大写)。
- 将结果保存到新文件中。
实现步骤
1. 读取文件
python
def read_file(filename):
"""逐行读取文件内容"""
with open(filename, 'r') as f:
for line in f:
yield line.strip()
2. 过滤数据
python
def filter_lines(min_length=10):
"""过滤长度大于等于 min_length 的行"""
while True:
line = yield
if len(line) >= min_length:
yield line
3. 转换数据
python
def convert_to_upper():
"""将行转换为大写"""
while True:
line = yield
yield line.upper()
4. 保存结果
python
def save_to_file(filename):
"""将结果保存到文件"""
with open(filename, 'w') as f:
while True:
line = yield
f.write(line + '\n')
5. 构建管道
python
def pipeline():
"""构建生成器管道"""
# 创建各阶段的生成器
reader = read_file('large_file.txt')
filterer = filter_lines()
converter = convert_to_upper()
saver = save_to_file('output.txt')
# 启动生成器
next(filterer)
next(converter)
next(saver)
# 构建管道
for line in reader:
filterer.send(line)
filtered_line = filterer.send(None)
if filtered_line is not None:
converter.send(filtered_line)
upper_line = converter.send(None)
saver.send(upper_line)
# 关闭管道
saver.send(None)
6. 使用管道
python
if __name__ == '__main__':
pipeline()
解释
- 生成器管道 :通过
send()
方法将数据在各个生成器之间传递。 - 惰性处理:数据逐行处理,避免一次性加载大量数据到内存。
- 模块化:每个阶段的功能独立,便于维护和扩展。
四、总结
- 生成器 通过
yield
表达式实现惰性计算与内存高效处理。 - 上下文管理器 通过
with
语句管理资源,确保资源正确释放。 - 生成器管道可以高效处理大文件,避免内存瓶颈。
五、课后练习
- 扩展生成器管道,增加更多处理阶段(如统计行数、计算平均值等)。
- 实现一个自定义上下文管理器,用于管理数据库连接。
- 使用协程实现一个简单的聊天服务器,支持多个客户端连接。
通过这些练习,进一步掌握生成器与上下文管理器的高级用法!