在实际的编码过程中,有时有一些任务,需要事先做一些设置,事后做一些清理,这时就需要python with出场了,with能够对这样的需求进行一个比较优雅的处理,最常用的例子就是对访问文件的处理。

一般访问文件资源时我们会这样处理:

f = open(r'c:\test.txt', 'r')
data = f.read()
f.close()

这样写没有错,但是容易犯两个毛病:
1. 如果在读写时出现异常而忘了异常处理。
2. 忘了关闭文件句柄

以下的加强版本的写法:

f = open(r'c:\test.txt', 'r')
try:data = f.read()
finally:f.close()

以上的写法就可以避免因读取文件时异常的发生而没有关闭问题的处理了。代码长了一些。
但使用with有更优雅的写法:

with open(r'c:\test.txt', 'r') as f:data = f.read()

说明:
with后面接的对象返回的结果赋值给f。此例当中open函数返回的文件对象赋值给了f.with会自已获取上下文件的异常信息。
with是如何做到的呢?
with后面返回的对象要求必须两__enter__()/__exit__()这两个方法,而文件对象f刚好是有这两个方法的,故应用自如。
pytho中官方定义说明如下(https://docs.python.org/2/reference/datamodel.html#context-managers):

object.__enter__(self)
进入与此对象相关的运行时上下文。with语句将将此方法的返回值绑定到语句的AS子句中指定的目标(如果有设置的话)object.__exit__(self, exc_type, exc_value, traceback)
退出与此对象相关的运行时上下文。参数描述导致上下文退出的异常。如果上下文运行时没有异常发生,那么三个参数都将置为None。
如果有异常发生,并且该方法希望抑制异常(即阻止它被传播),则它应该返回True。否则,异常将在退出该方法时正常处理。请注意, __exit__()方法不应该重新抛出传入的异常,这是调用者的职责。

下面举例说明他的原理:

1. 无异常发生时的例子:

#!/user/bin/env python3
#-*- coding:utf-8 -*-class Test:def __enter__(self):print('__enter__() is call!')return selfdef dosomething(self):print('dosomethong!')def __exit__(self, exc_type, exc_value, traceback):print('__exit__() is call!')print(f'type:{exc_type}')print(f'value:{exc_value}')print(f'trace:{traceback}')print('__exit()__ is call!')with Test() as sample:sample.dosomething()>>
__enter__() is call!
dosomethong!
__exit__() is call!
type:None
value:None
trace:None
__exit()__ is call!

以上的实例Text,我们注意到他带有__enter__()/__exit__()这两个方法,当对象被实例化时,就会主动调用__enter__()方法,任务执行完成后就会调用__exit__()方法,另外,注意到,__exit__()方法是带有三个参数的(exc_type, exc_value, traceback), 依据上面的官方说明:如果上下文运行时没有异常发生,那么三个参数都将置为None, 这里三个参数由于没有发生异常,的确是置为了None, 与预期一致.

2. 有异常发生时,会抛出异常的例子:
以下例子在上面稍做了一些修改,让运行时产生异常,看看这三个参数的赋值情况:

#!/user/bin/env python3
#-*- coding:utf-8 -*-class Test:def __enter__(self):print('__enter__() is call!')return selfdef dosomething(self):x = 1/0print('dosomethong!')def __exit__(self, exc_type, exc_value, traceback):print('__exit__() is call!')print(f'type:{exc_type}')print(f'value:{exc_value}')print(f'trace:{traceback}')print('__exit()__ is call!')# return Truewith Test() as sample:sample.dosomething()
>>
__enter__() is call!
Traceback (most recent call last):
__exit__() is call!
type:<class 'ZeroDivisionError'>File "C:/Users/xxx/PycharmProjects/Test1/test.py", line 23, in <module>
value:division by zerosample.dosomething()
trace:<traceback object at 0x000001C08CF32F88>File "C:/Users/xxx/PycharmProjects/Test1/test.py", line 10, in dosomething
__exit()__ is call!x = 1/0
ZeroDivisionError: division by zero

从结果可以看出, 在执行到dosomethong时就发生了异常,然后将异常传给了__exit__(), 依据上面的官方说明:如果有异常发生,并且该方法希望抑制异常(即阻止它被传播),则它应该返回True。否则,异常将在退出该方法时正常处理。当前__exit__并没有写明返回True,故会抛出异常,也是合理的,但是正常来讲,程序应该是不希望它抛出异常的,这也是调用者的职责,我们将再次修改__exit__, 将其返回设置为True,

3. 有异常发生时,不再抛出异常的例子:

在上面的例子上做点修改.
#!/user/bin/env python3
#-*- coding:utf-8 -*-class Test:def __enter__(self):print('__enter__() is call!')return selfdef dosomething(self):x = 1/0print('dosomethong!')def __exit__(self, exc_type, exc_value, traceback):print('__exit__() is call!')print(f'type:{exc_type}')print(f'value:{exc_value}')print(f'trace:{traceback}')print('__exit()__ is call!')return Truewith Test() as sample:sample.dosomething()>>
__enter__() is call!
__exit__() is call!
type:<class 'ZeroDivisionError'>
value:division by zero
trace:<traceback object at 0x000001C94E592F88>
__exit()__ is call!

从结果看,异常抛出被抑制了,符合预期。

python3,浅谈with的神奇魔法相关推荐

  1. python类构造方法缺省_浅谈python3 构造函数和析构函数

    要点: 1.魔法方法,被__双下划线所包围 在适当的时候自动被调用 2.在创建一个对象的时候,一定会调用构造函数 3. del析构函数,在del a对象的时候,并一定会调用该析构函数 只有当该对象的引 ...

  2. python post请求参数为list_浅谈python3发送post请求参数为空的情况

    post请求的时候如果不带参数,其实作用就跟get请求一样.我们在做接口测试的时候,发现开发就全部使用的post,get的作用就被这样的post空参数请求给替代了. 在Python代码请求,如下: c ...

  3. 为什么python打包的应用那么大_浅谈python3打包与拆包在函数的应用详解

    1.序列(拆包) *用作序列拆包:*可对字符串.列表.集合.元组.字典.数字元素等序列进行拆包 print(*(1,2,3,4,5,6)) #1 2 3 4 5 6 print(*[1,2,3,4,5 ...

  4. python矩形语句_浅谈Python3实现两个矩形的交并比(IoU)

    一.前言 因为最近刚好被问到这个问题,但是自己当时特别懵逼,导致没有做出来.所以下来后自己Google了很多IoU的博客,但是很多博客要么过于简略,要么是互相转载的,有一些博客图和代码还有点问题,也导 ...

  5. 浅谈Python3函数命名空间与作用域

    日期:2020年1月23日 作者:Commas 注释:前一章节讲述了命名空间和作用域的知识,现在我们来谈一谈Python3函数的命名空间吧. 如果您想了解更多有关Python的知识,那么请点<我 ...

  6. python实例编程_浅谈如何编程Python3——Python实例(3)

    浅谈如何编程Python3--Python实例(3) # 测试实例一 print("测试实例一") str= "runoob.com"print(str.isa ...

  7. python中rstrip用法_浅谈Python3中strip()、lstrip()、rstrip()用法详解

    简单来说,三种方法是为了删除字符串中不同位置的指定字符.其中,strip()用于去除字符串的首尾字符,同理,lstrip()用于去除左边的字符,rstrip()用于去除右边的字符 Python中有三个 ...

  8. python3打印如何换行_浅谈Python3中print函数的换行

    Python3中print函数的换行 最近看了看Python的应用,从入门级的九九乘法表开始,结果发现Python3.x和Python2.x真的是有太大的不同之处,就比如这里的换行处理,怕忘记先记下来 ...

  9. python3 nonzero_浅谈python numpy中nonzero()的用法

    nonzero函数返回非零元素的目录. 返回值为元组, 两个值分别为两个维度, 包含了相应维度上非零元素的目录值. import numpy as np A = np.mat([[0,1,2,3,4, ...

最新文章

  1. 北大教授张大庆:无线感知,让你变老也优雅
  2. 两款带有WiFI的MicroPython模块:ESP32,ESP8266
  3. vue 上传图片视频组件,可拍照选择照片,解决苹果手机拍照旋转问题
  4. (转载)机器学习知识点(十一)隐马尔可夫模型
  5. H.264码率控制机制
  6. Zabbix中文模式:图片下面的字符乱码
  7. mysql binlog 统计_对MySQL binlog日志解析,统计每张表的DML次数
  8. 英语阅读理解关于计算机,一篇摘选的关于计算机的英语阅读材料,对大家的英语也许会有提高!...
  9. android 崩溃捕获_Android从相机和图库捕获图像
  10. tesseract-ocr 识别中文扫描图片
  11. Gallery 3D+倒影 滑动切换图片示例
  12. php symfony2 laravel4 比较,LARAVEL4、Phalcon、Symfony2的优缺点?
  13. 8192网卡linux,记录Ubuntu14.04安装Realtek USB无线网卡(RTL8192)驱动
  14. 驾驶员监控系统 DMS
  15. DOC文档转换成WPS格式要怎样操作
  16. TensorFlow学习(三)——神经网络进阶
  17. 新版SpringCloudGateway网关 切面修改方法入参
  18. 2016--在技术的浪潮中自我实现
  19. 实验室预约管理系统 实验设备 笔记本
  20. 【许晓笛】49行代码就能发币?而且EOS连例子都给你了

热门文章

  1. android获取已连上热点设备名称,2、android获取连接到手机热点上的设备的信息
  2. 基于SpringBoot+layui研发的后台管理平台
  3. H5播放HLS之hls.min.js库
  4. MySQL(七)—— 分组查询
  5. 视频号和抖音号的区别
  6. c语言已知24有8个因子,C语言上机考试题二(2页)-原创力文档
  7. 二手房屋信息发布交易小程序开发制作功能
  8. 【驱动模块】 -- linux的背光(backlight)子系统【转】
  9. oracle 正数变负数
  10. 融资、量产和一栈式布局,这家Tier 1如此备战高阶智驾决赛圈