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. MySQL——设置库中的表以奇数自增

    语句 SHOW VARIABLES LIKE 'auto_inc%'; 查看auto_increment_increment的值是不是1,如果是就设置成2 ; 这样所有的表都会以奇数来自增了,因为这个 ...

  2. Codeforce Round #554 Div.2 C - Neko does Maths

    数论 gcd 看到这个题其实知道应该是和(a+k)(b+k)/gcd(a+k,b+k)有关,但是之后推了半天,思路全无. 然而..有一个引理: gcd(a, b) = gcd(a, b - a) = ...

  3. 字符串str的使用方法

    参考:https://www.cnblogs.com/cookie1026/p/6048092.html #!/usr/bin/env python # -*- coding:utf- -*- s = ...

  4. layui加载层

    layer.load(1, { shade: [0.5, '#000'], //0.5透明度的灰色背景 content: '注册中...', success: function (layero) { ...

  5. 老男孩Python全栈学习 S9 日常作业 006

    1.使用循环打印以下效果: 1: * ** *** **** ***** 2: ***** **** *** ** * 3: * *** ***** ******* ********* for i i ...

  6. Kubernetes之DaemonSet控制器

    DaemonSet 简介 DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本.当有 Node 加入集群时,也会为他们新增一个 Pod .当有 Node 从集群移除时,这些 P ...

  7. Ubuntu16下Hive 安装

    0.安装环境和版本 Ubuntu16,hadoop版本是2.7.2 ,选择Hive版本为  hive-2.1.17 1. Hive安装包下载 地址: https://mirrors.tuna.tsin ...

  8. [再寄小读者之数学篇](2014-05-28 Ladyzhenskaya 不等式)

    $$\bex f\in C_c^\infty(\bbR^2)\ra \sen{f}_{L^4}\leq \sqrt{2} \sen{f}_{L^2}^{1/2} \sen{\p_1f}_{L^2}^{ ...

  9. 大家都知道fastclick能解决300ms延迟,现在我们来看一下,使用方法

    1.在终端输入以下命令进行安装 npm install fastclick -S 2.在你用脚手架搭建好的项目中,找到mian.js这个入口文件,打开 3.在其中加入: import FastClic ...

  10. svn 支持中文显示

    https://blog.csdn.net/chentengkui/article/details/77543498 https://blog.csdn.net/bugall/article/deta ...