Python第三十九讲:with语句与上下文管理器(资源自动管理)
2026/9/8 16:23:17 网站建设 项目流程

大伙平常在读写文件之际肯定都见识过 with open() , 这便是最为经典的上下文管理器。在本节课当中要将 with 的底层原理彻彻底底弄明白, 学会自行去封装资源管理器, 这是开发项目时必须要掌握的知识点。

一、为什么需要with语句?

日常读取文件,传统写法:

data = f.read()

f.close()

问题: 要是read()在进行当中出现报错情况, 代码会发生中断, close()就不会被执行了, 且文件资源无法被释放出来, 从而造成资源泄露了。

于是有人用 try... 解决:

f = open("test.txt", "r", ="utf-8")

try:

data = f.read()

:

# 无论正常运行还是报错,一定会执行关闭

f.close()

代码冗长,重复度极高。

通过with语句, 其本质实际上就是try -的语法糖现象, 能够给我们自动完成释放资源的操作。

标准推荐写法:

data = f.read()

# 离开代码块,自动执行close(),无需手动关闭

二、上下文管理器协议(核心原理)

一个对象能够被 with 调用,必须实现两个魔法方法:

1. (self)

进入with代码块时自动执行,返回值赋值给 as 后的变量

2. (self, , , )

带有代码块一旦离开, 就会自动执行。不管是正常结束, 还是代码出现异常, 都会将其触发, 而这样是用来清理资源的。

案例:自定义计时器管理器

time

class Timer:

def (self):

self.start = time.()

print("开始执行任务")

self

def (self, , , ):

end = time.()

首先, 打印格式化字符串, 其中包含“任务结束”, 以及“耗时: ”, 再加上结束时间与开始时间相减后保留两位小数的结果, 以“秒”为单位。

# 使用

with Timer():

time.sleep(1.2)

print("正在运行业务代码")

运行观察:不管内部代码是否报错,最终都会打印耗时。

补充: 三个参数:异常类型、异常对象、异常堆栈。

要是方法返回True, 那么代码块内抛出的异常会被屏蔽;要是返回False, 异常将继续向外抛出。

三、简化写法:装饰器

每一次去书写类以及魔法方法的时候, 都是比较麻烦的, 内置了点, 仅仅只是使用生成器来快速对上下文管理器进行创建。

语法规则:

- yield之前:对应 逻辑

- yield之后:对应 清理逻辑

- yield的值,就是as接收的变量

from

time

@

def timer():

start = time.()

try:

yield # 交出控制权,执行with内部代码

:

end = time.()

把end减去start的结果, 保留两位小数, 以秒为单位, 用格式化字符串的写法, 输出“执行耗时: ”加上这个结果, 然后打印出来。

# 调用

with timer():

time.sleep(0.8)

print("测试代码")

改造,支持向外传递变量:

from

@

def (name):

print(f"【进入】{name}")

yield f"传入参数:{name}"

print(f"【退出】{name}")

with ("数据处理") as val:

print(val)

print("执行业务逻辑")

四、实际开发常用场景

1. 文件读写(最常用)

f.write("hello ")

2. 数据库连接:自动关闭连接、事务回滚

3. 线程锁:自动释放锁

4. 临时修改环境、临时切换目录,执行完毕自动恢复

5. 请求会话管理

五、多个with嵌套写法

方式1:连续书写(推荐)

使用打开文件操作, 以“a.txt”为文件名作为文件对象f1打开, 同时, 以“b.txt”为文件名作为文件对象f2打开。

print(f1.read(), f2.read())

方式2:多层缩进

with open("a.txt") as f1:

with open("b.txt") as f2:

pass

六、常见坑点

1. 切勿于with的内部情形之下, 对as所指示的变量进行再次赋值这一行为, 否则将会致使资源不能够依照正常的状况予以释放。

2. yield过后的代码务必得编写于内部之中, 以此确保在发生异常的状况下依旧能够执行清理操作。

3. 上下文管理器只作用于缩进内代码,退出缩进立刻清理资源

4. 猎取异常之时, 不得随意以True去遮蔽失误, 因其极易将程序漏洞隐匿起来。

七、课后练习

1. 以类的形式, 撰一个文件开启管理器, 自行开启、关上文件。

2. 借由 @ 去达成一个数据库模拟连接管理器, 当进入之时打印连接成功, 在退出之际打印关闭连接。

3. 思考:对比手动try-和with,分别适合什么场景

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询