纠结过去,担心未来,都不如抓住当下。过去是梦,未来是影,现在才是真真切的人生。
我们平时编程时尽量使用with自动关闭资源,这里就有个上下文管理器对象的概念,然后查找资料,对with的解释如下:with的有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。下面就讲下with语句以及上下文管理器对象,希望对你有帮助。
with语句
对于文件操作完成后,应该要关闭它,这是一个常识,因为打开的文件不仅占用了系统资源,而且可能影响其它程序或进程的操作,甚至会导致用户期望与实际操作结果不一样。with语句得语法为
1 | with 表达式 [as 目标]: |
with语句支持嵌套,支持多个with子句,它们两者可以相互转换。”with expr1 as e1,expr2 as e2”与下面的嵌套形式等价
1 | with expr1 as e1: |
with语句使用比较简单。如下面例子不使用with的时候代码如下:
1 | f = open('test.txt','w') |
使用with语句代码如下:
1 | with open('test.txt','w') as f: |
with语句可以在代码块执行完毕后,还原到进入该代码块时的现场(这句话要仔细理解,也就是说with里的代码块执行完后,会返回到刚刚进入with时的现场)。with语句代码块执行过程如下:
- 计算表达式的值,返回一个上下文管理器对象;
- 加载上下文管理器对象的
__exit__()
方法以备后用; - 调用上下文管理器对象的
__enter__()
方法; - 如果with语句中设置了目标对象,则将
__enter__()
方法的返回值赋值给目标对象(比如上面的f); - 执行with里的代码块;
- 如果步骤(5)代码正常结束,调用上下文管理器对象的
__exit__()
方法,返回值直接忽略; - 如果步骤(5)中代码异常,调用上下文管理器对象的
__exit__()
,并将异常类型、值以及traceback信息作为参数传递给__exit__()
方法。如果__exit__()
返回值为false,则异常会被重新抛出;如果返回的是true,异常被挂起,程序继续执行;
使用with的好处是无论程序以何种方式跳出with块,总能保证资源被正确关闭。下面介绍一下上下文管理器对象。
上下文管理器对象
with的神奇之处得益于一个成为上下文管理器的(context manager)的东西,它用来创建一个这样的对象:它定义程序运行时需要建立的上下文,处理程序的进入和退出,实现上下文管理协议,即在对象中定义__enter__()
和__exit__()
方法(这两个方法可以重载,这就说明,我们可以自定义属于自己的上下文管理器,待会儿再介绍),其中:
__enter__(self)
进入运行时的上下文,也就是进入上下文管理器时调用该函数,返回运行时的上下文对象,with语句中会将这个返回值绑定到目标对象上(上面的例子就是绑定到f上)。顺便说下上下文表达式(Context Expression),上下文表达式指with 语句中跟在关键字 with 之后的表达式,该表达式要返回一个上下文管理器对象,该对象就被赋值给了目标对象。
__exit__(self,exception_type,exception_value,traceback)
退出运行时的上下文,定义在块执行(或终止)之后上下文管理器应该做什么。它可以处理异常、清理现场或者处理with块中语句执行完成后需要处理的动作。exception_type,exception_value,traceback三个参数代表的意思分别是异常的类型、值和追踪信息。如果没有异常,3个参数均设为None。此方法返回值为True或者False,分别指示被引发的异常得到了还是没有得到处理。如果返回False,引发的异常会被传递出上下文。这个在前面简单的提到过,希望你能结合上下文仔细理解这些东西。
实际上任何实现了上下文协议的对象都可以称为一个上下文管理器,文件也是实现了这个协议的上下文管理器,它们都能够与with语句兼容。文件对象的__enter__()
和__exit__()
属性如下:
1 | >>>f.__enter__ |
当然我们也可以定义自己的上下文管理器,只要实现了上下文协议便可以和with语句一起使用。如下面例子:
1 | class OpenFile(object): |
上下文管理器主要作用于资源共享,因此在实际应用中__enter__()
和__exit__()
方法基本用于资源分配以及释放相关的工作,如打开/关闭文件、异常处理、断开流的连接、锁分配等。为了更好的辅助上下文管理器,Python还提供了contextlib模块,这个下次有机会再讲。