ith替代了之前在python里使用try...finally来做清理工作的方法。基本形式如下:

with expression [as variable]:
with-block

当expression执行的时候,返回一个支持context management protocol(有__enter__(), __exit__()方法)的对象

这个对象的__enter__()方法在with-block执行前运行,该方法返回的结果赋给variable(如果variable存在的话)

with-block执行之后,__exit__()方法被调用,在这里可以执行清理工作

在实际的编码过程中,有时有一些任务,需要事先做一些设置,事后做一些清理,这时就需要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 self def 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 self def dosomething(self):
x = 1/0
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!')
# return True with 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 zero
sample.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 self def dosomething(self):
x = 1/0
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!')
return True with 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!

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

转载自:https://blog.csdn.net/lxy210781/article/details/81176687

整理一下python中with的用法的更多相关文章

  1. python 中del 的用法

    python中的del用法比较特殊,新手学习往往产生误解,弄清del的用法,可以帮助深入理解python的内存方面的问题. python的del不同于C的free和C++的delete. 由于pyth ...

  2. python中argparse模块用法实例详解

    python中argparse模块用法实例详解 这篇文章主要介绍了python中argparse模块用法,以实例形式较为详细的分析了argparse模块解析命令行参数的使用技巧,需要的朋友可以参考下 ...

  3. 【313】python 中 print 函数用法总结

    参考:python 中 print 函数用法总结 参考:Python print() 函数(菜鸟教程) 参考:Python 3 print 函数用法总结 目录: 字符串和数值类型 变量 格式化输出 p ...

  4. [zz]【整理】Python中Cookie的处理:自动处理Cookie,保存为Cookie文件,从文件载入Cookie

    http://www.crifan.com/python_auto_handle_cookie_and_save_to_from_cookie_file/ #!/usr/bin/python # -* ...

  5. python中MySQLdb模块用法实例

    篇文章主要介绍了python中MySQLdb模块用法,以实例形式详细讲述了MySQLdb模块针对MySQL数据库的各种常见操作方法,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了python中 ...

  6. 【整理】Python中实际上已经得到了正确的Unicode或某种编码的字符,但是看起来或打印出来却是乱码

    转自:http://www.crifan.com/python_already_got_correct_encoding_string_but_seems_print_messy_code/ [背景] ...

  7. 整理:WPF中XmlDataProvider的用法总结

    原文:整理:WPF中XmlDataProvider的用法总结 一.目的:了解XmlDataProvider中绑定数据的方法 二.绑定方式主要有三种: 1.Xaml资源中内置: <!--XPath ...

  8. 整理:WPF中CommandBindings的用法

    原文:整理:WPF中CommandBindings的用法 目的:了解一下CommandBindings.InputBindings.ICommandSource中在WPF中扮演什么样的角色 Comma ...

  9. python中hashlib模块用法示例

    python中hashlib模块用法示例 我们以前介绍过一篇Python加密的文章:Python 加密的实例详解.今天我们看看python中hashlib模块用法示例,具体如下. hashlib ha ...

随机推荐

  1. windows下零基础gulp构建

    在学习前,先谈谈大致使用gulp的步骤,给读者以初步的认识.首先当然是安装nodejs,通过nodejs的npm全局安装和项目安装gulp,其次在项目里安装所需要的gulp插件,然后新建gulp的配置 ...

  2. mysql 单列无重复

    ALTER TABLE jeesite.bb_bill ADD UNIQUE (object_id);

  3. ECShop安装及错误修复

    ecshop 商城的安装及出现错误的解决 听语音 | 浏览:600 | 更新:2016-03-04 16:02 | 标签:错误 安装 电子商务 1 2 3 4 5 6 7 分步阅读 昨天第一次安装ec ...

  4. springboot+mybatis+cucumber

    import org.junit.runner.RunWith; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucu ...

  5. pkuseg:一个多领域中文分词工具包

    pkuseg简单易用,支持细分领域分词,有效提升了分词准确度. 目录 主要亮点 编译和安装 各类分词工具包的性能对比 使用方式 相关论文 作者 常见问题及解答 主要亮点 pkuseg具有如下几个特点: ...

  6. Hadoop记录- Yarn scheduler队列采集

    #!/bin/sh ip=10.116.100.11 port=8088 export HADOOP_HOME=/app/hadoop/bin rmstate1=$($HADOOP_HOME/yarn ...

  7. [物理学与PDEs]第1章第5节 Maxwell 方程组的数学结构, 电磁场的波动性 5.3 电磁场的波动性, 自由电磁波

    1. 由 Maxwell 方程组易知 $$\beex \bea \cfrac{1}{c^2}\cfrac{\p^2{\bf E} }{\p t^2}-\lap{\bf E}  &=-\sex{ ...

  8. EasyUI datagrid 的多条件查询

    <script type="text/javascript">         $(function () {            $("#dg" ...

  9. JS获取当月第一天和最后一天

    /** * 获取当前月的第一天 */function getCurrentMonthFirst(){ var date=new Date(); date.setDate(1); return date ...

  10. mysql 分库分表 ~ 柔性事务

    一 定义 TCC方案是可能是目前最火的一种柔性事务方案二 具体 内容 TCC=try(预设)-confrim(应用确认)-canal(回滚取消)三 目的 解决跨服务调用场景下的分布式事务问题,避免使用 ...