python之contextmanager

一、contextmanager有什么用?

contextmanager是 Python 标准库contextlib模块提供的同步上下文管理器装饰器,核心作用是简化同步上下文管理器的实现。

在没有contextmanager之前,实现一个上下文管理器需要手动定义类,并实现__enter__()和__exit__()两个魔法方法;而使用contextmanager,只需装饰一个同步生成器函数,即可快速封装出上下文管理器,无需手动实现魔法方法,代码更简洁优雅。

二、适用场景

当你在同步代码中需要管理「需要先获取、使用后必须释放 / 清理」的资源时,contextmanager是最优选择,

典型场景包括:

  • 同步文件操作:普通文件的打开 / 关闭,自动释放文件句柄(Python 内置open()本身就是上下文管理器,此处用于演示封装思想)
  • 同步数据库连接:如pymysql操作 MySQL,自动建立 / 关闭数据库连接
  • 同步锁 / 资源占用:如threading.Lock,自动获取 / 释放锁,避免死锁
  • 临时资源创建 / 清理:如临时目录创建、临时文件写入后自动删除、日志上下文切换等

简单来说:同步场景 + 资源需要自动管理(获取 + 释放),就用contextmanager。

三、核心使用规则

@contextmanager装饰的同步生成器函数,必须满足固定结构:

  • 函数用def定义(同步函数,无async关键字)
  • 函数内部包含且仅包含一个yield关键字(用于分割「资源获取」和「资源释放」逻辑)
  • 代码结构分为三部分:
    1. yield 之前:对应上下文管理器的__enter__()方法,负责获取 / 初始化资源,执行时机是进入with语句块时
    2. yield 关键字:将需要使用的资源「返回」给with语句的as变量(可返回单个资源,也可返回None),同时暂停函数执行,交出控制权给with语句块
    3. yield 之后:对应上下文管理器的__exit__()方法,负责释放 / 清理资源,执行时机是离开with语句块时(无论代码块正常结束还是发生异常,都会执行)
  • 推荐将yield之后的清理逻辑放在finally块中,确保资源释放的可靠性(即使中间代码抛出异常,清理逻辑也能执行)

四、代码示例

我们实现一个「同步文件读写工具」,使用contextmanager封装普通文件的打开 / 关闭,确保文件句柄自动释放,无需手动调用close(),与之前的异步示例形成对比,更易理解。

# 1. 导入必要模块(contextmanager是Python内置,无需额外安装依赖)fromcontextlibimportcontextmanager# 2. 使用@contextmanager装饰同步生成器,实现同步上下文管理器@contextmanagerdeffile_manager(file_path:str,mode:str="r",encoding:str="utf-8"):""" 同步文件管理器:自动打开/关闭文件,封装同步文件操作的资源管理 :param file_path: 文件路径 :param mode: 文件打开模式(r/w/a等) :param encoding: 文件编码 """# 初始化文件句柄file_handle=Nonetry:# -------- 第一步:yield之前(对应__enter__()):获取/初始化资源 --------file_handle=open(file_path,mode=mode,encoding=encoding)print(f"✅ 同步打开文件:{file_path}(模式:{mode})")# -------- 第二步:yield关键字:返回资源给with语句,暂停函数执行 --------yieldfile_handle# 将文件句柄传递给with ... as 后的变量# -------- 第三步:yield之后(对应__exit__()):释放/清理资源(finally确保必执行) --------finally:iffile_handle:file_handle.close()print(f"❌ 同步关闭文件:{file_path}")# 3. 使用同步上下文管理器(配合with语句)defmain():# 测试文件路径test_file_path="test_sync.txt"# 示例1:同步写入文件内容withfile_manager(test_file_path,mode="w")asf:f.write("Hello, contextmanager!\n")f.write("这是同步文件写入测试\n")# 示例2:同步读取文件内容withfile_manager(test_file_path,mode="r")asf:content=f.read()print("\n📄 文件内容:")print(content)# 4. 运行同步主函数if__name__=="__main__":main()

关键解析

  • 进入with语句块时,自动执行yield之前的open()逻辑,打开文件并获取文件句柄
  • with语句块内操作文件句柄,执行完成后自动离开代码块,触发finally中的close()逻辑,关闭文件
  • 即使文件写入 / 读取过程中抛出异常(例如手动添加raise Exception(“测试异常”)),finally块中的清理逻辑依然会执行,确保文件句柄被释放,不会造成资源泄露

异常处理

@contextmanagerdeffile_manager(file_path:str,mode:str="r",encoding:str="utf-8"):file_handle=Nonetry:file_handle=open(file_path,mode=mode,encoding=encoding)print(f"✅ 同步打开文件:{file_path}(模式:{mode})")yieldfile_handle# 此处抛出的异常会被传递到with代码块exceptFileNotFoundErrorase:print(f"❌ 错误:文件不存在 -{e}")raise# 可选:重新抛出异常,让调用方感知并处理exceptExceptionase:print(f"❌ 操作文件出错:{e}")raisefinally:iffile_handle:file_handle.close()print(f"❌ 同步关闭文件:{file_path}")

扩展示例

演示contextmanager用于管理临时目录(创建→使用→自动删除),更贴近实际项目中的资源管理场景:

importosimportshutilfromcontextlibimportcontextmanager@contextmanagerdeftemporary_directory(dir_path:str="temp_dir"):"""同步临时目录管理器:自动创建→使用→删除临时目录"""# 1. 初始化:创建临时目录try:os.makedirs(dir_path,exist_ok=True)print(f"✅ 成功创建临时目录:{dir_path}")yielddir_path# 返回临时目录路径给with语句finally:# 2. 清理:删除临时目录及其内容ifos.path.exists(dir_path):shutil.rmtree(dir_path)print(f"❌ 成功删除临时目录:{dir_path}")# 使用临时目录deftest_temp_dir():withtemporary_directory()astemp_dir:# 在临时目录中创建文件temp_file=os.path.join(temp_dir,"test.txt")withopen(temp_file,"w")asf:f.write("临时文件内容")print(f"📄 临时文件已创建:{temp_file},文件大小:{os.path.getsize(temp_file)}字节")if__name__=="__main__":test_temp_dir()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1136592.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新手必看:JavaScript堆内存问题入门指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个交互式学习工具,通过简单的示例和逐步引导,帮助初学者理解JavaScript堆内存分配失败的常见原因(如内存泄漏、大对象分配等)…

背调软件如何重塑企业人才风控的底层逻辑

在信息高度不对称的招聘市场中,一份精心修饰的简历可能隐藏着企业难以承受的风险。近年来,超过60%的企业在招聘中层以上岗位时遭遇过履历信息失实的情况,其中近三分之一因此遭受了直接经济损失。当传统的人工背调在效率与深度之间陷入两难时&…

Thinkphp-Laravel+uniapp微信小程序的汽车线上车辆租赁管理系统的设计与实现_

目录 摘要关键词 项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理 摘要 该系统基于ThinkPHP-Laravel框架与Uniapp技术栈,设计并实现了一款面向汽车租赁行业的线上车辆租赁管理系统。后端采用ThinkPHP-Laravel混合架构,结合…

STM32版500e代码移植优化与开关霍尔算法应用:性能卓越,低速稳定,技术文档齐全

500e HALL STM32版 500e代码精简之后移植到103上,带载能力强,低速性能优秀,效果见视频。 增加开关霍尔算法,可对比无感角度与传感器角度,方便优化性能! 提供: 1、代码 2、电路板电机一套&…

比手动快10倍!自动化处理STEP7许可证问题

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个自动化许可证管理工具,专门针对STEP7 BASIC。功能:1. 自动备份许可证;2. 许可证状态监控;3. 异常自动恢复;4. 多…

LISTAGG、XMLAGG

LISTAGG(TO_CHAR(orp.id),;) WITHIN GROUP (ORDER BY orp.id) ORP_IDS,XMLAGG(XMLPARSE(content to_char(orp.id) || ; wellformed) ORDER BY orp.id).getclobval() ORP_IDS,注:to_char保证分组之后列转行的字符类型,不然会有空格,当列转行字…

Thinkphp-Laravel基于Javaspring的贵州旅游系统vue

目录系统架构与技术栈功能模块设计技术创新与亮点应用价值与特色项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理系统架构与技术栈 该系统采用前后端分离架构,后端基于ThinkPHP和Laravel框架开发,借鉴了JavaSpring的设计理…

Thinkphp-Laravel+uniapp微信小程序的便捷理疗店服务预约系统的研究与实现

目录摘要项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理摘要 随着移动互联网技术的快速发展,微信小程序因其轻量化、便捷性及广泛的用户基础,成为服务行业数字化转型的重要工具。本研究基于ThinkPHP-Laravel框架与UniApp技…

必看!2026年EOR名义雇主服务品牌排行榜,助你快速展开全球业务

2026年EOR名义雇主服务品牌排行榜为企业提供了丰富的选择,帮助他们在全球市场上茁壮成长。这些服务提供商不仅能够有效应对复杂的合规要求,还能提供灵活、高效的用工解决方案。分析这些品牌,可以看到它们在合规能力、服务质量和覆盖区域等方面…

AI助力漏洞复现:Vulhub自动化搭建指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个基于Vulhub的自动化漏洞复现系统,要求:1.支持通过自然语言描述漏洞类型自动匹配Vulhub镜像 2.自动生成docker-compose配置文件 3.提供漏洞验证的测…

考虑电动汽车的微网优化:微电网各组成部分个体模型与粒子群优化算法的经济调度

考虑电动汽车的微网优化,给出微电网各组成部分的个体模型,并采用粒子群优化算法进行经济调度。光伏板在正午的阳光下滋滋作响,隔壁储能站的锂电池组闪着幽幽蓝光。充电桩前停着三辆电动网约车,司机老张叼着烟头抱怨:&q…

铌酸锂微盘的光学模式分析是集成光子学里挺有意思的活儿。今儿咱们用COMSOL整一波基模求解,顺带聊聊怎么避开那些让人头秃的坑点。先甩个基础模型练手

Comsol铌酸锂微盘模式求解。 几何建模这块儿,直接在COMSOL里撸个圆柱体就完事。直径设10微米,厚度0.5微米,注意Z轴方向要和晶体c轴对齐。材料库里的铌酸锂参数得手动调各向异性,别直接用默认值: model.param.set(d, …

AI如何助力Vue-Pure-Admin开发?智能代码生成实战

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 基于Vue-Pure-Admin框架,使用Kimi-K2模型生成一个后台管理系统的基础代码结构。要求包含:1.基于Vue3TypeScript的初始化项目 2.集成Element-Plus UI组件库 …

Thinkphp-Laravel基于Java的课程教学辅助网站 作业考试管理系统设计vue

目录 基于ThinkPHP/Laravel与Vue的课程教学辅助系统设计摘要 项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理 基于ThinkPHP/Laravel与Vue的课程教学辅助系统设计摘要 该系统采用前后端分离架构,后端基于ThinkPHP/Laravel框架&#xf…

从零实现 es6 函数扩展的多参数处理功能

深入函数心脏:手写实现 ES6 多参数处理机制你有没有想过,当你写下这样一行代码时:function greet(name Guest, ...messages) {console.log(Hello ${name}, ...messages); }JavaScript 引擎在背后究竟做了什么?这看似简单的语法糖…

2026年品牌排行榜:TOP5 EOR名义雇主人力资源解决方案推荐

在2026年品牌排行榜中,EOR名义雇主服务成为企业拓展国际市场的重要工具。通过这些服务,企业能够快速合规地雇佣全球人才,降低进入新市场的复杂性。这些解决方案为公司提供了高效的薪酬管理、合规事务处理和员工福利方案,确保企业在…

企业必看|一文读懂GB/T 4857.23、:运输包装gbt4857.23振动测试的安全指南

物流运输环节,包装件总要经受公路颠簸、铁路震动等复杂工况的考验——多少优质产品因包装抗振性能不足,在途出现破损、功能失效,动辄造成数万甚至数十万损失?GB/T 4857.23标准作为运输包装振动测试的核心依据,正是破解…

Thinkphp-Laravel+uniapp微信小程序的健康食品零食商城积分兑换的设计与实现_

目录摘要项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理摘要 健康食品零食商城积分兑换系统基于ThinkPHP-Laravel框架与Uniapp微信小程序开发,实现用户积分管理与商品兑换功能。系统采用前后端分离架构,后端使用ThinkPHP-…

和测试角色相关的问题

有了独立的测试角色之后,是不是就万事大吉了?未必,分工意味着一件事要分给别人去工作。让别人做事,并且依赖别人做出的结果,这会出现一些问题。 问题1 既然有专人负责,那我就不用负责了! 生活中有一个常见的歪理:既然…

欧姆龙CP1H项目程序,程序包含四轴?一个NC413轴控制模块一起五个,有轴的点动,回零,相对...

欧姆龙CP1H项目程序,程序包含四轴?一个NC413轴控制模块一起五个,有轴的点动,回零,相对与绝对定位,扩展两个I/O模块,整个项目的模块都有:主控程序,复位程序,手动,程序流程…