python之上下文管理器——with语句详解

上下文管理器
一、基本语法
with EXPR as VAR
	pass
  • 其中的EXPR是一个表达式,返回的是一个对象,var用来保存EXPR表达式返回的对象,可以有单个或者多个返回值。
>>>以最常用的with为例:
  • with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的清理操作,释放资源,比如,文件使用后的自动关闭、线程中锁的自动获取和释放等;

  • with语句即上下文管理器,含有__enter____exit__方法的对象都是上下文管理器;

    • enter:在执行with语句之前,首先执行该方法,通常返回一个实例对象,如果with语句有as目标,则将对象赋值给as目标;
    • exit:在执行with语句结束后,自动调用__exit__方法,用户释放资源,若此方法返回布尔值为True,程序会忽略异常。(什么时候能返回True)
  • 操作文本对象的时候,几乎所有的人都会让我们要用with open,这就是一个上下文管理器的一种。比如:

	with open('1.txt') as f:
		print(f.readllines())

输出结果:

	'print'
	'True'
  • 表达式open(‘1.txt’)返回是一个_io.TextIOWrapper 类型的变量用f接受到。在with语句块中就可以使用这个变量操作文件。执行with这个结构之后。f会自动关闭。相当于自带了一个finally。
  • 但是with本身并没有异常捕获的功能,如果发生了运行时异常的情况,它照样可以关闭文件释放资源。

另外:

	try:
	    with open('1.txt') as f2:
	        print(f2.read())
	        f2.seek(-5,os.SEEK_SET)
	except ValueError as e:
	    print("error")
	    print(f2.closed)

输出结果:

'print'
'error'
'True'
二、如何写上下管理器
  • 要自己实现这样一个上下文管理,要先知道上下文管理协议。

  • 简单点说,就是在一个类里,实现了__enter__和__exit__的方法

  • 实现这个类的示例:

class Resource()
	
	def __enter__(self):
		# 连接资源
		print('==connect to resource==')
	def __exit__(self):
		# 关闭资源连接
		print('==close resource connection==')
	def operate(self):
		# 运行中
		print('==in operation==')
		
if __name__ == '__main__':
	with Resource() as res:
		res.operate()
  • 输出结果:
1.'==connect to resource=='
2.'==in operation=='
3.'==close resource connection=='

从这个示例可以很明显的看出,在编写代码时,可以将资源的连接或者获取放在__enter__中,而将资源的关闭写在__exit__中。

三、为什么要用资源管理器
  • 在处理异常的时候,通常会使用try..except...来捕获异常。这样做一个不好的地方是,在代码的主程序中,会有大量的异常处理,这会很大的影响我们的可读性。
  • 好的一点做法是,可以使用with将异常的处理隐藏起来。
  • 仍然是以上面的代码为例,我们将1/0这个一定会抛出异常的代码写在operate
class Resource()
	def __enter__(self):
		# 连接资源
		print('==connect to resource==')
	def __exit__(self):
		# 关闭资源连接
		print('==close resource connection==')
	def operate(self):
		# 运行中
		1/0
with Resource() as res:
	res.operate()
  • 运行一下会发现,居然不会报错。
  • 这就是上下文管理协议的强大之处,异常可以在__exit__进行捕获,并由你自己决定如何处理,是抛出呢?还是在这里解决呢?在__exit__里返回True(没有return,就默认为return False),就相当于告诉 Python 解释器,这个异常我们已经捕获了,不需要再往外抛了。
  • 在写__exit__函数时,需要注意的是,他必须有三个参数:
    • 1.exc_type:异常类型
    • 2.exc_val:异常值
    • 3.exc_tb:异常的错误栈信息
  • 当主程序代码没有报异常时,这三个参数都将为None。

部分参考:https://juejin.im/post/5c87b165f265da2dac4589cc

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值