1. 先搞懂:with语句为啥能“自动管资源”? 🤔

关键字

:上下文管理协议、enter、__exit__内容详解: 之前用

with open()

时,文件会自动关闭——这不是“魔法”,是因为文件对象遵守了

上下文管理协议

:只要一个类实现了

__enter__

__exit__

两个方法,它的对象就能用在

with

语句里:

  • __enter__with语句开始时执行(比如“打开文件”“连接数据库”),返回的对象会赋值给as后的变量;
  • 🧹 __exit__with语句结束时执行(不管代码是否出错),负责“清理资源”(比如“关闭文件”“断开数据库连接”)。

类比:

with

像“酒店前台”——

__enter__

是“帮你开房门、递房卡”,

__exit__

是“你退房时自动收房卡、关水电”,不用你自己操心!

二、实战:做一个“数据库连接上下文管理器”

2. 动手写:数据库连接的上下文管理器——自动连/断 🗄️

关键字

:自定义上下文管理器、数据库资源管理 内容详解: 结合第7章的数据库操作,写一个“自动管理数据库连接”的上下文管理器类:

import mysql.connector

# 定义遵守上下文管理协议的类
class DBContextManager:
    def __init__(self, host, user, password, database):
        # 初始化数据库配置(状态)
        self.db_config = {
            "host": host,
            "user": user,
            "password": password,
            "database": database
        }
        self.conn = None  # 保存数据库连接
    
    # with开始时:连接数据库
    def __enter__(self):
        self.conn = mysql.connector.connect(**self.db_config)
        return self.conn  # 返回连接对象给with的as变量
    
    # with结束时:关闭连接(不管是否出错)
    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.conn:
            self.conn.close()
        # 处理异常(可选):返回True表示异常已处理,False则抛出
        return False

用起来超省心——不用手动关连接:

# 使用上下文管理器:自动连接、自动关闭
with DBContextManager(
    host="localhost",
    user="root",
    password="你的密码",
    database="web_log_db"
) as conn:
    cursor = conn.cursor()
    cursor.execute("SELECT COUNT(*) FROM access_log")
    count = cursor.fetchone()[0]
    print(f"总访问次数:{count}")
# 代码块结束后,conn已经自动关闭!

哪怕代码块里抛异常(比如SQL写错了),

__exit__

也会执行,保证连接被关闭——彻底解决“忘记关资源”的问题!

三、进阶:上下文管理器优化Web应用代码

3. 落地Web应用:用上下文管理器简化日志代码 🕸️

关键字

:Web应用集成、代码简化 内容详解: 把上下文管理器用到Flask Web应用中,简化“写数据库日志”的代码(对比第7章的代码):

from flask import Flask, request
import datetime

app = Flask(__name__)

# 复用上面的DBContextManager类
class DBContextManager:
    # ...(和前面的定义一样)

# 写日志的视图函数:用上下文管理器简化
@app.route("/")
def home():
    now = datetime.datetime.now()
    user_ip = request.remote_addr
    action = "访问首页"
    
    # 用with自动管理数据库连接
    with DBContextManager(
        host="localhost",
        user="root",
        password="你的密码",
        database="web_log_db"
    ) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "INSERT INTO access_log (log_time, user_ip, action) VALUES (%s, %s, %s)",
            (now, user_ip, action)
        )
        conn.commit()
    
    return "首页(日志已存,连接已自动关闭)"

if __name__ == "__main__":
    app.run(debug=True)

对比之前的代码:不用写“连接→关闭”的重复逻辑,代码更短、更安全——这就是上下文管理协议的价值!

四、上下文管理器的“高级玩法”:处理异常

4. 进阶技巧:在__exit__里处理异常 🚨

关键字

:__exit__参数、异常处理 内容详解:

__exit__

有三个参数:

exc_type

(异常类型)、

exc_val

(异常值)、

exc_tb

(异常追踪栈)——可以用它们在

with

结束时处理异常:

class SafeDBContextManager(DBContextManager):
    def __exit__(self, exc_type, exc_val, exc_tb):
        # 先执行父类的关闭逻辑
        super().__exit__(exc_type, exc_val, exc_tb)
        
        # 如果有异常,打印日志(不抛出)
        if exc_type:
            print(f"数据库操作出错:{exc_val}")
            return True  # 返回True表示“异常已处理,不用向上抛”
        return False

用这个类时,即使代码块里出错,也只会打印日志,不会让Web应用崩溃——适合生产环境的“容错处理”!

五、总结:上下文管理协议的核心价值

5. 划重点:上下文管理协议的“灵魂” 🎯

关键字

:资源安全、代码简洁、可复用 内容详解: 上下文管理协议解决了两个核心问题:

  • 🔒 资源安全:不管代码是否正常执行/抛异常,资源都会被清理(不会出现“数据库连接泄露”);
  • 📝 代码简洁:把“打开/关闭资源”的重复逻辑封装,业务代码更聚焦核心功能;
  • 🧩 可复用:写好的上下文管理器可以在多个项目里直接用(比如文件、数据库、网络连接等场景)。

这也是Python“优雅编程”的体现——用协议规范行为,让代码既安全又简洁!