环境管理器

python 复制代码
#coding=utf-8

class Cooker:  # 厨师
    def open_gas(self):
        print("正在打开天然气")

    def close_gas(self):
        print("正在关闭天然气")

    def doworks(self):
        print("正在制作小甜饼")

    def __enter__(self):
        self.open_gas()
        return self  # 此对象将被 as 绑定

    def __exit__(self, exc_type, exc_value, exc_tb):
        self.close_gas()
        if exc_type is None:
            print("with语句正常退出")
        else:
            print("with语句异常退出,", exc_value)


with Cooker() as c:
    c.doworks()  # 工作中
    3/0  # ZeroDivisionError
    c.doworks()


# 正常处理流程
# c = Cooker()
# c.open_gas()
# c.doworks()
# 3/0
# c.doworks()
# c.close_gas()

这是一个上下文管理器 (context manager)的示例:

把"开燃气→做活→关燃气"这种成对资源管理 封装进 with 语句里,不管中途是正常结束 还是出异常 ,都能确保最后关掉燃气

现实对照:

  • open_gas():打开资源(文件/网络连接/锁/数据库事务...)

  • doworks():执行任务

  • close_gas():释放资源(关闭/解锁/提交或回滚...)

with 语句会调用:

  • 进入时:__enter__

  • 退出时:__exit__无论有没有异常都会调用)

执行流程图

A) 正常情况(无异常)

python 复制代码
with Cooker() as c:
    c.doworks()

流程:
__enter__  → open_gas
    ↓
块内执行   → doworks
    ↓
__exit__   → close_gas(exc_type 等参数都是 None)

B) 异常情况(比如块内 3/0)

python 复制代码
with Cooker() as c:
    c.doworks()
    3/0

流程:
__enter__  → open_gas
    ↓
块内执行   → ZeroDivisionError 抛出
    ↓
__exit__   → close_gas(收到异常信息 exc_type/ exc_value/ exc_tb)
    ↓
__exit__ 返回值决定是否"吃掉异常":
   - 返回 True  → 异常被抑制,不再往外抛
   - 返回 False/None → 异常继续向外抛

用 try/finally 等价写法

下面两段是效果等价的:

写法 1:with(推荐)

python 复制代码
with Cooker() as c:
    c.doworks()
    3/0
    c.doworks()

写法 2:手写 try/finally

python 复制代码
c = Cooker()
c.open_gas()
try:
    c.doworks()
    3/0
    c.doworks()
finally:
    c.close_gas()      # 无论是否异常,最终都会执行

差别:with 更简洁、不会忘记关资源,还能把异常信息交给 __exit__ 决定是否抑制。

控制异常

python 复制代码
    def __exit__(self, exc_type, exc_value, exc_tb):
        self.close_gas()  # 无论正常/异常退出,都先把资源关了
        if exc_type is None:
            print("with 语句正常退出")
        else:
            print("with 语句异常退出:", exc_value)

         关键点:是否抑制异常?
         若 return True ,异常被"吃掉",外面感觉不到
         若 return False/None(当前代码等价于 None),异常会继续向外抛
         这里没写 return,相当于返回 None → 不抑制异常
相关推荐
m0_748554815 小时前
golang如何实现用户订阅偏好管理_golang用户订阅偏好管理实现总结
jvm·数据库·python
QQ1__8115175155 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态5 小时前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子5 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室5 小时前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI5 小时前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing5 小时前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者5 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册5 小时前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
有谁看见我的剑了?5 小时前
linux 添加硬盘后系统识别不到硬盘处理
linux·运维·服务器