当前位置: 首页 > 后端技术 > Python

你只知道with,那whowho呢?

时间:2023-03-26 16:14:14 Python

在长期的编程实践中,我们一定有过使用如下代码的经历:withopen("test.txt","r",encoding="utf-8")asf:s=f.readlines()有人知道这样写的原因;但很多人不知道,只是简单的“别人都这样写,我就应该这样写”。同时,很多知其所以然的人也只是知其然不知其所以然:with语句可以为我们自动关闭打开的文件对象。但这是通过什么机制实现的呢?1.with和异常处理我们知道,如果不使用with语句,那么正常读写一个文件应该经历这几个过程:打开文件、操作文件、关闭文件。用Python代码表示如下:f=open("test.txt","r",encoding="utf-8")s=f.readlines()f.close()一般情况下是这样的no问题。接下来,我们人为制造一点“意外”:将打开文件对象时指定的模式从“r”改为“w”。f=open("test.txt","w",encoding="utf-8")s=f.readlines()f.close()此时当程序执行到第二行读取文件内容,将抛出错误:Traceback(mostrecentcalllast):File"test_with.py",line2,ins=f.readlines()io.UnsupportedOperation:notreadable然后...可怕的情况发生了。Python以未处理的异常退出,并且第2行之后的代码尚未执行,因此f.close()永远没有机会执行。一个如鬼魅般打开的文件对象,就像一个漂浮在记忆海洋中的人。没有人知道他是谁,从哪里来,要到哪里去。这样,每当抛出异常时,就会产生这样的杂散对象。久而久之,浩瀚的记忆海洋化作了游子的乐园,其他人无从思考。归根结底,我们发现这个问题的关键在于“打开-操作-关闭”文件的管道操作可能抛出异常。于是我们想到了使用Python提供的大杀器来处理这些异常:try-catch。修改之前的异常处理代码:try:f=open("test.txt","a",encoding="utf-8")s=f.readlines()except:print("Anexceptionoccurred")finally:f.close()这样,通过附加的finally语句,无论文件操作是否抛出异常,都可以保证打开的文件被关闭。这样就避免了持续占用资源造成资源泄露的问题。其实with语句为我们提供了一个try-catch-finally的封装。编程的时候,看似只是随便with,其实暗地里保证了类似上述代码的异常处理机制。2.contextmanagerwith生效需要作用于contextmanager-stop,什么是contextmanager?长话短说,实现__enter__和__exit__方法的对象。在进入运行时上下文之前加载这两个方法以供使用。进入此运行时上下文时,将调用__enter__方法;在退出上下文之前,调用__exit__方法。这里的“runtimecontext”可以简单理解为提供一些特殊配置的代码作用域。当我们使用open("test.txt","r",encoding="utf-8")asf的代码时,Python会先open("test.txt","r",encoding="utf-8")来获取上下文管理器。这里比较特别的是文件对象本身就是Python中的上下文管理器,所以我们可以使用open函数作为表达式进行求值。然后调用__enter__方法,返回的对象绑定到我们指定的标识符f。文件对象的__enter__返回的是文件对象本身,所以这段代码将打开的“test.txt”文件对象绑定到标识符f。接着执行with语句块的内容。最后,调用__exit__退出with语句块。根据上面的内容,我们也可以自己构造一个上下文管理器(注意两个特性方法的参数一定要和协议保持一致):classtestContextManager:def__enter__(self):print("进入运行时上下文,call__enter__method")def__exit__(self,exc_type,exc_value,traceback):print("退出运行时上下文,调用__exit__方法")withtestContextManager()aso:pass输出结果:进入运行时上下文,调用__enter__的方法退出运行时上下文并调用__exit__方法。with语句之所以能够替代繁琐的异常处理语句,是因为上下文管理器按照协议实现了__enter__和__exit__方法,with语句保证了异常发生时__exit__方法可以执行,退出相关运行时语境。在这个方法中,我们可以完成一些必要的清理工作。总结在本文中,我们解释了with语句的内部逻辑并尝试实现自定义上下文管理器。相信大家对with的作用有了更深的理解。with语句不仅可以用来读写文件,还可以用来自动获取和释放锁,保存和恢复全局状态等,更多实用的方法留给大家去探索。以上就是本次分享的全部内容。想了解更多python知识,请前往公众号:Python编程学习圈,发“J”免费领取,每日干货分享