Python学习之路(19)——Python的with语句
with语句时从Python2.5开始引入的一种与异常处理相关的功能(2.5版本需要通过from __future__ import with_statement导入后方能使用),从2.6版本开始缺省可用。
with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”工作,释放资源。比如文件使用后的自动关闭、线程中锁的自动获取和释放等。
举例文件处理,首先需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。
1、with语句
with 表达式 [as 目标]:
代码块
with语句也支持嵌套,支持多个with子句,比如:
with expr1 as e1:
with expr2 as e2:
与下面的形式等价:
with expr1 as e1,expr2 as e2:
下面介绍with处理文件操作的方法,当不使用with语句时,代码如下:
f = open('test.txt','w')
try:
f.write("hello")
finally:
f.close() #这句很容易被忘记,这也是为什么推荐使用with
而使用with的代码如下:
with open('test.txt','w') as f:
f.write("hello")
如何理解?
with语句可以在代码块执行完毕后,还原到进入该代码块的现场(也就是说with里的代码块执行完成后,会返回到刚刚进入with时的现场)。
with语句代码块执行过程如下:
(1)计算表达式的值,返回一个上下文管理器对象
(2)加载上下文管理器对象的__exit__()方法以备后用
(3)调用上下文管理器对象的__enter__()方法
(4)如果with语句中设置了目标对象,则将__enter__()方法的返回值赋值给目标对象(比如上面的f)
(5)执行with里的代码块
(6)如果步骤(5)代码正常结束,调用上下文管理器对象的__exit__()方法,返回值直接忽略
(7)如果步骤(5)中代码异常,调用上下文管理器对象的__exit__(),并将异常类型、值以及traceback信息作为参数传递给__exit__()方法。如果__exit__()返回值为false,则异常会被重新抛出;如果返回的是true,异常被挂起,程序继续执行。
从上面可以看出,使用with的好处是无论程序以何种方式跳出with语句块,总能保证资源被正确关闭。
2、上下文管理器对象
上下文管理协议(Context Management Protocol):包含魔法方法__enter__()和__exit__(),支持该协议的对象要实现这两种方法。
上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了__enter__()和__exit__()方法。上下文管理器定义了执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。通常使用with语句调用上下文管理器,也可以通过直接调用其方法来使用。
运行时上下文(runtime context):由上下文管理器创建,通过上下文管理器的__enter__()和__exit__()方法实现,__enter__()方法在语句体执行之前进入运行时上下文,__exit__()方法在语句体执行完后从运行时上下文退出。
上下文表达式(Context Expression):with语句中跟踪关键字with之后的表达式,该表达式要返回一个上下文管理器对象。
语句体(with-body):with语句的代码块,在执行语句体之前会调用上下文管理器的__enter__()方法,执行完语句体之后会执行__exit__()方法。
with context_expression [as target(s)]:
with-body
这里context_expression要返回一个上下文管理器对象,该对象并不赋值给as子句中的target(s),如果指定了as子句的话,会将上下文管理器的__enter__()方法的返回值赋值给target(s)。target(s)可以是单个变量,也可以是元组。
上下文管理器主要作用于资源共享,因此在实际应用中__enter__()和__exit__()方法基本用于资源分配以及释放相关的工作,如打开/关闭文件、异常处理、断开流的连接、锁分配等。
浙公网安备 33010602011771号