面向对象高级之魔法方法
一、__enter__ 和 __exit__
python中实现了__enter__和__exit__方法支持上下文管理器协议。上下文管理器就是支持上下文管理器协议的对象,它是为了with而生。当with语句在开始运行时,会在上下文管理器对象上调用 __enter__ 方法。with语句运行结束后,会在上下文管理器对象上调用 __exit__ 方法
1.with语句是什么?
1 | 有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。 |
如果不用with语句,代码如下:
1 2 3 4 5 6 7 8 9 | try : # 1. [进入] f = open( 'a.txt' , 'r' , encoding= "utf-8" ) # 2. [执行] print(f.read()) finally : if f: # 3. [退出] f.close() |
python操作文件的流程一般就是这三步:
1 2 3 4 5 6 7 8 | [进入]用只读方式打开文件 如果文件不存在,open()函数就会抛出一个IOError的错误,并且给出错误码和详细的信息告诉你文件不存在 [执行]读取文件内容 如果文件打开成功,接下来,调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示 [退出]关闭打开的文件 文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的 |
思考为什么关闭文件操作一定要放在finallly语句里?
1 | 由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用 try ... finally 来实现。 |
发现共性:
1 | 我们发现其实这种过程化的语句有共性,比如说在进去一个片段前必须做某种超赞,处理工作后又需要执行一个结束操作。比如上面的这段代码: |
1 2 3 | finally : if f: f.close() |
就可以做一个封装。
使用with语句后,我们是这样打开一个文件的:
1 2 | with open( "a.txt" , "r" , encoding= "utf-8" ) as f: print(f.read()) |
这个with语句和前面的try ... finally结构是一样的,但是代码更佳简洁,并且不必调用f.close()方法。
2.with语句的执行原理
从解释器的角度去理解with语句执行流程:
with语句的基本形式是:
1 2 | with 表达式 as 变量: 语句块 |
这样的一段代码可以称为一个上下文(context),在执行with语句时,解释器会先求出表达式的值,这个值(对象)是一个上下文管理器,并且这个对象拥有如下类构造方法:
1 2 3 4 5 6 7 | def __enter__(): # 描述进入上下文的动作 pass def __exit__(): # 描述退出上下文的动作 pass |
with语句在求出这个上下文管理器对象之后,自动执行进入方法
,并将这个对象的返回值赋值于 as 之后的变量,然后执行语句块。然后在退出上下文前,自动执行对象的退出方法
。
python系统和标准库的一些类型定义了这对操作,可以直接用于with语句。比如文件对象就直接支持这一对操作,因此可以用在with语句的头部。
如果你也有类似的计算过程需要抽取出来,那么可以自定义一个类,并且包含进入、退出方法。
用途或者说好处:
1 2 3 | 1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预 2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处 |
3.实现自定义with 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class MyClass: def __init__(self,file_name,mode= 'r' ,encoding= 'utf-8' ): self.fine_name = file_name self.mode = mode self.encoding = encoding def __enter__(self): print( "进入上下文" ) self.file = open(self.fine_name,mode=self.mode,encoding=self.encoding) return self.file def __exit__(self, exc_type, exc_val, exc_tb): print( "退出上下文" ) self.file.close() with MyClass( 'test.txt' , 'w' ,encoding= 'utf-8' ) as f: f.write( "test msg" ) print( 'hello world' ) |
"一劳永逸" 的话,有是有的,而 "一劳永逸" 的事却极少
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具