python with语句的原理与用法详解


Posted in Python onMarch 30, 2020

本文实例讲述了python with语句的原理与用法。分享给大家供大家参考,具体如下:


之前看到一篇博客说博主python面试时遇到面试官提问with的原理,而那位博主的博文没有提及with原理,故有此文。

关于with语句,官方文档中是这样描述的:

The with statement is used to wrap the execution of a block with methods defined by a context manager (see section With Statement Context Managers). This allows common try...except...finally usage patterns to be encapsulated for convenient reuse.

with_stmt ::= "with" with_item ("," with_item)* ":" suite

with_item ::= expression ["as" target]

The execution of the with statement with one “item” proceeds as follows:

The context expression (the expression given in the with_item) is evaluated to obtain a context manager.

The context manager's __exit__() is loaded for later use.

The context manager's __enter__() method is invoked.

If a target was included in the with statement, the return value from __enter__() is assigned to it.

Note

The with statement guarantees that if the __enter__() method returns without an error, then __exit__() will always be called. Thus, if an error occurs during the assignment to the target list, it will be treated the same as an error occurring within the suite would be. See step 6 below.

The suite is executed.

The context manager's __exit__() method is invoked. If an exception caused the suite to be exited, its type, value, and traceback are passed as arguments to __exit__(). Otherwise, three None arguments are supplied.

谷歌翻译成中文就是:

with语句用于使用由上下文管理器定义的方法来封装块的执行(请参见使用语句上下文管理器一节)。 这允许通用的try…except…finally使用模式被封装以便于重用【这句话大概意思就是“with语句”类似于try…except…finally封装之后的的情况】。

带有一个“项目”的with语句的执行过程如下:
1.上下文表达式(在with_item中给出的表达式)被评估以获得上下文管理器。【会区分类型来处理,如文件,进程等都可以使用with语句】
2.上下文管理器的__exit __()被加载供以后使用。【负责上下文的退出】
3.上下文管理器的__enter __()方法被调用。【负责上下文的进入】
4.如果在with语句中包含目标,则将__enter __()的返回值分配给它。【如果with后面跟着as 对象(如with open() as f),那么此对象获得with上下文对象的__enter__()的返回值,(附:应该是类似操作数据库时的连接对象和游标的区别)】

注意
with语句保证,如果__enter __()方法返回时没有错误,那么将始终调用__exit __()。 因此,如果在分配给目标列表期间发生错误,它将被视为与套件内发生的错误相同。 请参阅下面的第6步。

5.该套件已执行。【意思就是语句体中的过程执行完毕,执行完毕就到第六步--调用__exit__()来退出】
6.上下文管理器的__exit __()方法被调用。 如果异常导致套件退出,则其类型,值和回溯作为参数传递给__exit __()。 否则,将提供三个无参数。

关于退出返回值:

If the suite was exited due to an exception, and the return value from the __exit__() method was false, the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the statement following the with statement.

If the suite was exited for any reason other than an exception, the return value from __exit__() is ignored, and execution proceeds at the normal location for the kind of exit that was taken.

中文:
如果套件由于异常而退出,并且__exit __()方法的返回值为false,则会重新对异常进行重新评估。 如果返回值为true,则异常被抑制,并继续执行with语句后面的语句。

如果套件由于除了异常之外的任何原因而退出,则__exit __()的返回值将被忽略,并且执行将在正常位置继续进行。

意思就是:

如果是异常退出,那么会返回false,(根据文档中的exit的描述“that __exit__() methods should not reraise the passed-in exception; this is the caller's responsibility.”,大概意思就是exit()不会处理异常,会重新抛出异常抛出给外面,由调用者处理,因为这是调用者的责任)

如果返回 True,则忽略异常,不再对异常进行处理【(在exit内部处理完异常后,可以让”__exit__()”方法返回True,此时该异常就会不会再被抛出,with会认为它的执行体没有发生异常)】

(with会识别返回值,根据返回值来处理,如果是False,那么with会将执行体中的异常抛出,如果是True,那么with会认为没有发生异常(忽略异常),而继续执行外面的语句,但由于内部调用的了__exit__(),所以在异常之后的语句是不会运行的

附上一个文档中提供的一个关于with中使用锁的例子:

python with语句的原理与用法详解

几个测试:

1.执行体中发生异常:

import time
class myContextDemo(object):
 def __init__(self,gen):
  self.gen = gen
 def __enter__(self):
  print("enter in ")
  return self.gen
 def __exit__(self, exc_type, exc_val, exc_tb):
#exc_type是exception_type exc_val是exception_value exc_tb是exception_trackback
  print("exit in ")
  if exc_type is None:#如果是None 则继续执行
   print("None:",exc_type, exc_val, exc_tb)

  else: #异常不为空时执行,这一步,如果with语句体中发生异常,那么也会执行
   print("exception:", exc_type, exc_val, exc_tb)
   print("all done")

if __name__=="__main__":
 gen=(i for i in range(5,10))
 G=myContextDemo(gen)
 with G as f :
  print("hello")
  for i in f:
   print(i,end="\t")
  #测试1:执行体中发生异常
  raise Exception("母鸡啊")
 print("main continue")

结果显示:python with语句的原理与用法详解

1.抛出异常后,后面main continue不再执行

2.__exit__()中的else会执行

测试2:当else中强制返回为True时:

import time
class myContextDemo(object):
 def __init__(self,gen):
  self.gen = gen
 def __enter__(self):
  print("enter in ")
  return self.gen
 def __exit__(self, exc_type, exc_val, exc_tb):
#exc_type是exception_type exc_val是exception_value exc_tb是exception_trackback
  print("exit in ")
  if exc_type is None:#如果是None 则继续执行
   print("None:",exc_type, exc_val, exc_tb)

  else: #异常不为空时执行,这一步,如果with语句体中发生异常,那么也会执行
   print("exception:", exc_type, exc_val, exc_tb)
   print("all done")
   return True #这里如果返回true可以看到发生异常后,main continue可以执行
   #即,如果exc_type是true,那么会继续执行,实际上,也可以在这里处理一下异常再返回true


if __name__=="__main__":
 gen=(i for i in range(5,10))
 G=myContextDemo(gen)
 with G as f :
  print("hello")
  for i in f:
   print(i,end="\t")
  raise Exception("母鸡啊")
  # print("continue")#这里不会执行
 print("main continue")

结果显示:python with语句的原理与用法详解

1.返回True之后,with会忽略异常,继续执行,所以这里“main continue”能执行

2.即使忽略异常,在with体中异常之后的语句依旧不会执行

附:理论上可以在返回True之前处理一下异常

PS:如果大家想要了解得更详细,可以自己尝试去读一下官方文档。

附上关于with语句的详细介绍官方文档:https://www.python.org/dev/peps/pep-0343/

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
在Python中操作字符串之startswith()方法的使用
May 20 Python
Python缩进和冒号详解
Jun 01 Python
python多线程方式执行多个bat代码
Jun 07 Python
Django框架教程之正则表达式URL误区详解
Jan 28 Python
python 自定义异常和异常捕捉的方法
Oct 18 Python
python 自定义装饰器实例详解
Jul 20 Python
Python实现bilibili时间长度查询的示例代码
Jan 14 Python
tensorflow 实现自定义layer并添加到计算图中
Feb 04 Python
Python异常原理及异常捕捉实现过程解析
Mar 25 Python
Python中的流程控制详解
Feb 18 Python
Python爬虫进阶之Beautiful Soup库详解
Apr 29 Python
Python代码风格与编程习惯重要吗?
Jun 03 Python
对django 2.x版本中models.ForeignKey()外键说明介绍
Mar 30 #Python
Python进程的通信Queue、Pipe实例分析
Mar 30 #Python
基于Django OneToOneField和ForeignKey的区别详解
Mar 30 #Python
django 扩展user用户字段inlines方式
Mar 30 #Python
Python3标准库之threading进程中管理并发操作方法
Mar 30 #Python
解决django xadmin主题不显示和只显示bootstrap2的问题
Mar 30 #Python
Python2 与Python3的版本区别实例分析
Mar 30 #Python
You might like
PHP之sprintf函数用法详解
2014/11/12 PHP
php使用Session和文件统计在线人数
2015/07/04 PHP
Laravel框架下载,安装及路由操作图文详解
2019/12/04 PHP
PHP程序员必须知道的两种日志实例分析
2020/05/14 PHP
javascript OFFICE控件测试代码
2009/12/08 Javascript
Javascript 匿名函数及其代码模式原理
2010/03/19 Javascript
js 如何实现对数据库的增删改查
2012/11/23 Javascript
如何使用jquery动态加载js,css文件实现代码
2013/04/03 Javascript
利用JS判断用户是否上网(连接网络)
2013/12/23 Javascript
javascript使用avalon绑定实现checkbox全选
2015/05/06 Javascript
如何屏蔽防止别的网站嵌入框架代码
2015/08/24 Javascript
基于jQuery通过jQuery.form.js插件实现异步上传
2015/12/13 Javascript
动态生成的DOM不会触发onclick事件的原因及解决方法
2016/08/06 Javascript
AngularJS实现在ng-Options加上index的解决方法
2016/11/03 Javascript
[38:30]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第一场2
2014/05/24 DOTA
[01:03]悬念揭晓 11月26日DOTA2完美盛典不见不散
2017/11/23 DOTA
Python编程中的文件读写及相关的文件对象方法讲解
2016/01/19 Python
python简单实现刷新智联简历
2016/03/30 Python
详解Python3中字符串中的数字提取方法
2017/01/14 Python
Python实现复杂对象转JSON的方法示例
2017/06/22 Python
基于python实现KNN分类算法
2020/04/23 Python
利用Pandas和Numpy按时间戳将数据以Groupby方式分组
2019/07/22 Python
Python实现微信机器人的方法
2019/09/06 Python
Python计算矩阵的和积的实例详解
2020/09/10 Python
python爬虫今日热榜数据到txt文件的源码
2021/02/23 Python
CSS3 :not()选择器实现最后一行li去除某种css样式
2016/10/19 HTML / CSS
意大利男装网店:Vrients
2019/05/02 全球购物
Foot Locker加拿大官网:美国知名运动产品零售商
2019/07/21 全球购物
Kiwi.com中国:找到特价机票并发现新目的地
2019/10/27 全球购物
DOUGLAS波兰:在线销售香水和化妆品
2020/07/05 全球购物
社区领导班子四风问题原因分析及整改措施
2014/09/28 职场文书
2015年学校体育工作总结
2015/04/22 职场文书
表扬信范文
2019/04/22 职场文书
JavaScript实现简单图片切换
2021/04/29 Javascript
Python实现单例模式的5种方法
2021/06/15 Python
Python Pandas模块实现数据的统计分析的方法
2021/06/24 Python