2025-08-21 Python进阶6——迭代器生成器与with
文章目录
- 1 迭代器与生成器
- 1.1 迭代器
- 1.1.1 基本使用
- 1.1.2 手动迭代(带异常处理)
- 1.1.3 自定义迭代器
- 1.2 生成器
- 1.2.1 工作原理
- 1.2.2 斐波那契数列示例
- 1.3 推导式
- 1.3.1 列表推导式
- 1.3.2 字典推导式
- 1.3.3 集合推导式
- 1.4.4 元组推导式(生成器表达式)
- 2 with关键字
- 2.1 基本语法
- 2.2 常用场景
- 2.2.1 文件操作(最典型)
- 2.2.2 数据库连接
- 2.2.3 线程锁
- 2.3 工作原理:上下文管理协议
- 2.4 自定义上下文管理器
- 2.4.1 方式 1:类实现
- 2.4.2 方式 2:使用 contextlib 模块
- 2.5 最佳实践
1 迭代器与生成器
1.1 迭代器
- 迭代器是可记住遍历位置的对象
- 只能向前遍历,不能后退
- 核心方法:
iter()
创建迭代器,next()
获取下一个元素
1.1.1 基本使用
# 创建迭代器
list = [1, 2, 3, 4]
it = iter(list) # 创建迭代器对象# 访问元素
print(next(it)) # 1
print(next(it)) # 2# 使用for循环遍历
for x in it:print(x, end=" ") # 3 4
1.1.2 手动迭代(带异常处理)
import sysit = iter([1, 2, 3, 4])while True:try:print(next(it))except StopIteration:sys.exit() # 迭代结束时退出
1.1.3 自定义迭代器
需实现两个方法:
__iter__()
: 返回迭代器对象本身__next__()
: 返回下一个元素,迭代结束时抛出StopIteration
class MyNumbers:def __iter__(self):self.a = 1return selfdef __next__(self):if self.a <= 20: # 限制迭代次数x = self.aself.a += 1return xelse:raise StopIteration # 结束迭代# 使用自定义迭代器
myclass = MyNumbers()
for x in iter(myclass):print(x) # 输出1到20
1.2 生成器
- 使用
yield
关键字的函数称为生成器 - 生成器是特殊的迭代器,可逐步产生值
- 调用生成器函数返回的是迭代器对象
1.2.1 工作原理
- 执行到
yield
时返回值并暂停 - 下次调用时从暂停处继续执行
- 适合处理大量数据或无限序列
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
1.2.2 斐波那契数列示例
def fibonacci(n):a, b, counter = 0, 1, 0while True:if counter > n:returnyield a # 返回当前斐波那契数a, b = b, a + bcounter += 1# 使用生成器
f = fibonacci(10)
for x in f:print(x, end=" ") # 0 1 1 2 3 5 8 13 21 34 55
1.3 推导式
推导式是一种简洁的数据处理语法,可从一个序列构建新序列,支持列表、字典、集合和元组。
1.3.1 列表推导式
格式:[表达式 for 变量 in 列表 if 条件]
实例 1:过滤并转换
names = ['Bob','Tom','alice','Jerry','Wendy','Smith']
new_names = [name.upper() for name in names if len(name) > 3]
# 结果: ['ALICE', 'JERRY', 'WENDY', 'SMITH']
实例 2:数值筛选
multiples = [i for i in range(30) if i % 3 == 0]
# 结果: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
1.3.2 字典推导式
格式:{key表达式: value表达式 for 变量 in 集合 if 条件}
实例 1:字符串长度字典
listdemo = ['Google','Runoob', 'Taobao']
newdict = {key: len(key) for key in listdemo}
# 结果: {'Google': 6, 'Runoob': 6, 'Taobao': 6}
实例 2:数字平方字典
dic = {x: x**2 for x in (2, 4, 6)}
# 结果: {2: 4, 4: 16, 6: 36}
1.3.3 集合推导式
格式:{表达式 for 变量 in 序列 if 条件}
实例 1:计算平方
setnew = {i**2 for i in (1, 2, 3)}
# 结果: {1, 4, 9}
实例 2:字符筛选
a = {x for x in 'abracadabra' if x not in 'abc'}
# 结果: {'d', 'r'}
1.4.4 元组推导式(生成器表达式)
格式:(表达式 for 变量 in 序列 if 条件)
注意:返回生成器对象,需用tuple()
转换
实例:生成数字元组
a = (x for x in range(1, 10)) # 生成器对象
print(tuple(a)) # 转换为元组
# 结果: (1, 2, 3, 4, 5, 6, 7, 8, 9)
2 with关键字
with
关键字用于上下文管理,简化资源(如文件、数据库连接)的获取与释放,确保资源使用后被正确清理。
对比传统资源管理方式:
传统方式(try-finally) | with 语句 |
---|---|
需手动调用 close() | 自动释放资源 |
代码冗长 | 简洁直观 |
易遗漏关闭操作 | 异常安全 |
传统文件操作示例:
file = open('test.txt', 'r')
try:content = file.read()
finally:file.close() # 必须手动关闭
2.1 基本语法
with 表达式 [as 变量]:# 代码块(使用资源)
- 表达式返回上下文管理器对象
as 变量
:可选,将对象赋值给变量- 代码块执行完毕后,自动触发资源清理
2.2 常用场景
2.2.1 文件操作(最典型)
# 读取文件
with open('example.txt', 'r') as file:content = file.read()print(content)
# 退出代码块后,文件自动关闭# 同时操作多个文件
with open('in.txt', 'r') as infile, open('out.txt', 'w') as outfile:outfile.write(infile.read().upper()) # 转换为大写并写入
2.2.2 数据库连接
import sqlite3with sqlite3.connect('mydb.db') as conn:cursor = conn.cursor()cursor.execute('SELECT * FROM users')print(cursor.fetchall())
# 连接自动关闭,无需手动调用 close()
2.2.3 线程锁
import threadinglock = threading.Lock()with lock:# 临界区代码(自动加锁/解锁)print("线程安全的操作")
2.3 工作原理:上下文管理协议
支持 with
的对象需实现两个方法:
__enter__()
:进入上下文时调用,返回值赋给as
后的变量__exit__()
:退出上下文时调用,负责资源清理
执行流程:
- 执行表达式,获取上下文管理器
- 调用
__enter__()
方法,进入上下文 - 执行代码块
- 无论是否发生异常,都调用
__exit__()
方法
异常处理机制
__exit__()
方法接收三个参数:exc_type
(异常类型)、exc_val
(异常值)、exc_tb
(追踪信息)
- 返回
True
:表示异常已处理,不再传播 - 返回
False
/None
:异常继续向外传播
2.4 自定义上下文管理器
2.4.1 方式 1:类实现
class Timer:def __enter__(self):import timeself.start = time.time()return self # 可通过 as 接收def __exit__(self, exc_type, exc_val, exc_tb):import timeprint(f"耗时: {time.time() - self.start:.2f}秒")return False # 不抑制异常# 使用
with Timer() as t:sum(range(10000000)) # 执行耗时操作
2.4.2 方式 2:使用 contextlib 模块
from contextlib import contextmanager@contextmanager
def tag(name):print(f"<{name}>") # __enter__ 部分yield # 暂停,执行代码块print(f"</{name}>") # __exit__ 部分# 使用
with tag("h1"):print("这是标题内容")# 输出:
# <h1>
# 这是标题内容
# </h1>
2.5 最佳实践
- 优先使用 with:处理文件、网络连接、锁等资源时,必用
with
- 精简代码块:
with
内只写与资源相关的操作 - 多资源管理:一个
with
可同时管理多个资源(用逗号分隔) - 异常处理:自定义上下文时,明确是否需要抑制异常
with
语句通过自动化资源管理,大幅提升了代码的可读性和可靠性,是 Python 中处理资源的首选方式。