最近在学习Flask框架,看到AppContext类可以使用with控制LocalStack栈的压栈和出栈,就多了解一下with的用法
起因
再了解Flask的应用上下文的时候,正好看到了多种写法,正好趁这个机会,好好了解下with的作用。
为什么要用with编写代码
python是一门追求优雅的语言,所以对于一些常见的常见的感觉比较臃肿的代码,做了简化的操作,并不是说必须使用,不过想成为一名合格的pythoner,还是要多了解一下python的特性
贴一段伪代码:
try:
pass
except Exception:
pass
finally:
pass
with 上下文管理器(后面会提到):
pass
作用上来说,两种写法效果是一样的。
使用with常见概念
- 实现了上下文协议的对象才能使用with
- 实现了上下文协议的对象,通常称为上下文管理器
- 上下文协议需要实现两个魔法方法(enter,exit)
- with同行的语句,一般称为上下文表达式,它必须返回一个上下文管理器
with的使用场景
这里以数据库操作为例
- 连接数据库
- 对数据库的一些操作(sql)
- 操作完成,释放资源(断开连接)
在with的语法糖中,我们只用在乎如何编写第2步的代码
第1步,第3步会在魔法方法__enter__,__exit__中执行
很大程度上简化了代码的工作量
初入with
如图,执行with的语句会先从enter开始,再执行with下的语句,最后执行exit的语句,这里有个问题,就是为什么obj_a为None,在对文件的操作中,经常使用到 as f 这样的写法,这里为什么不行呢?
现在提出一个概念,as并不是将一个变量名指向上下文管理器,实际上as后面的变量是__enter__方法的返回值,如图所示。
接下来我们看一些__exit__这个方法,它做了什么事,修改一下代码。这里看一下__exit__的参数是干什么的,这3个参数只有当with语句出现异常的时候才会有参数,可以再这里对异常进行捕获处理。
如图
- return True 的时候默认为exit已经做了异常处理,在with里不会在抛出一个异常
- return False 或者不返回的时候,会继续抛出异常
回到开头,AppContent对象就是在__enter__,__exit__完成了应用上下文的压栈和出栈
这就是我理解中with的用法,如果有不同的看法,欢迎在评论区留言