环境管理器

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 → 不抑制异常
相关推荐
IT_陈寒6 小时前
JavaScript数组排序踩的坑,差点让我加班到凌晨
前端·人工智能·后端
风骏时光牛马6 小时前
提示词工程:大模型交互的核心构建艺术
前端
我命由我123456 小时前
Linux - Linux/POSIX 路径斜杠折叠规则
linux·运维·服务器·android studio·android jetpack·android-studio·android runtime
xx~t6 小时前
嵌入式——Linux软件编程——网络1
linux·c语言·网络·vscode·网络协议
今日无bug7 小时前
大模型的回答是怎么一个字一个字蹦出来的?前端流式输出解析
前端·llm·agent
计算机魔术师7 小时前
Anthropic 复盘 Claude 模型越权访问真实系统事件并改进对齐与安全措施
前端
谢白羽7 小时前
SGLang的AWQ量化笔记
笔记·python·sglang
掘金者阿豪7 小时前
Seedance 2.0/2.5 虚拟素材能跨 Key 共用吗?一次讲清 Asset ID、账号隔离与 SaaS 素材架构
前端·后端
用户50093768390397 小时前
热敏小票 Web 打印:我在 58/80mm 上折腾的两周
前端·vue.js
XGM7 小时前
一个前端新手的"顿悟"时刻:DOM树、渲染原理和JS动态渲染
前端