with 语句那点事
来源:互联网 发布:淘宝足球竞猜 编辑:程序博客网 时间:2024/05/20 21:58
在操作打开读取文件时,经常会看到如下代码:
with open('python.txt') as f:
for line in f:
print line
代码非常简洁,但是你是否深入理解这其中具体流程呢?
这段代码的作用是:根据文件名打开一个文件,如果无异常抛出,把文件对象赋值给f,然后用迭代器遍历文件中每一行,当完成时,关闭文件;而无论在这段代码的任何地方,如果发生异常,此时文件仍会被关闭。
你是否好奇,没有异常处理,没有 try ... except ... finally ... 的代码块,异常是如何处理的呢?
这是通过上下文对象来完成处理的。with 语句的通用结构如下:
with context_expr as var:
with_suite
其中,context_expr 为一上下文表达式,执行此表达式会返回一个上下文管理器。上下文管理器的职责是提供一个上下文对象,这是通过调用 __context__() 方法来完成的,这个方法返回上下文对象。上下文管理器本身也可以是上下文对象,即调用 __context__() 方法返回其本身。
上下文对象有什么特点呢?顾名思义,上下文,上文和下文,分别需要实现两个方法:
__enter__() 方法将完成 with 语句块执行前的所有准备工作,如果 with 语句后面跟了 as var 语句,则 var 即为 __enter__() 方法的返回值。
__exit__() 方法将完成 with 语句块执行后的所有处理工作,__exit__() 方法有3个参数,如果 with 语句正常结束,三个参数全部都是 None;如果发生异常,三个参数的值分别等于调用 sys.exc_info() 函数返回的三个值:类型(异常类)、值(异常实例)和跟踪记录(traceback),相应的跟踪记录对象。
由此可见,并非所有的对象都是上下文对象,那么常用的有哪些?小编常用的主要有:
file
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
这几种,这几种有什么特点?你会发现这几种都是资源。没错,with 语句很常用的功能,就是在执行语句块前申请获取相关的资源,而在 with 语句块执行完成之后,需要释放相关资源。
当然,明确了上下文对象的原理,我们也可以自己定义上下文对象:
class A:
def __enter__(self):
print '__enter__() called'
def __exit__(self, type, value, traceback):
print '__exit__() called'
if type is ZeroDivisionError:
print('Please DO NOT Divide By Zero!')
return True
with A() as a:
print('In With Code Block!')
b = 1/0
运行的结果如下:
__enter__() called
In With Code Block!
__exit__() called
Please DO NOT Divide By Zero!
可以发现,异常被正确处理了。 注意,遇见异常处理后需要返回 True,告诉解释器异常被正确处理了,否则会抛出异常。
在 Python 中,contextlib 模块允许我们使用其中的 contextmanager 函数作为装饰器,来创建一个上下文管理器。这样,就不需要定义上下文对象的两个方法 __enter__() 和 __exit__() (实际是 contextmanager 函数来完成转换),只需实现有一个 yield 语句的生成器,使得 yield 返回值为 __enter__ () 方法返回的值即可。
在使用 @contextmanager 装饰的生成器中,yield 语句将函数的定义体分成两部分:第一部分是yield 语句前面的所有代码,在 with 代码块开始前(即解释器调用 __enter__ () 方法时)执行,yield 的返回值即为 __enter__ () 方法的返回值; 第二部分是 yield 语句后面的代码,在 with 代码块结束时(即调用 __exit__() 方法时)执行。
由此,我们可以把自己实现的上下文对象改写为如下形式:
from contextlib import contextmanager
@contextmanager
def A():
try:
print '__enter__() called'
yield
except ZeroDivisionError:
print('Please DO NOT Divide By Zero!')
finally:
print '__exit__() called'
with A():
print('In With Code Block!')
b = 1/0
运行结果为:
__enter__() called
In With Code Block!
Please DO NOT Divide By Zero!
__exit__() called
异常也被正确处理了。
你是否学会了 with 语句的使用,是否深入理解了上下文对象?
- with 语句那点事
- SQL的那点事之语句大全
- 面试那点事
- 公司那点事
- 编程那点事!!
- 公务员那点事
- 毕业那点事
- JVM 那点事
- C++那点事
- 【粗心】那点事
- 【春运】那点事
- 内存那点事
- 程序员那点事
- Ext那点事
- Ext那点事
- 学习那点事
- 数组那点事
- 上班那点事
- [转]C语言开发函数库时利用不透明指针对外隐藏结构体细节
- Feed Happy Fish
- 今日头条成功的核心技术秘诀是什么?深度解密个性化资讯推荐技术 本文作者:AI研习社2017-07-05 12:24 导语:从“内行”的角度解密个性化资讯推荐技术。 雷锋网按:本文系知名 IT 技术资
- 【致敬ImageNet】ResNet 6大变体:何恺明,孙剑,颜水成引领计算机视觉这两年
- 新学习CSS特性总结
- with 语句那点事
- springboot配置多模块项目
- 精简的大数运算
- 定义一个返回内存的函数
- redis for all I know
- 如果我不曾遗忘,希望你也一样坚持
- 如何成为架构师系列:前言
- Servlet实现文件下载
- vim模式下文件的编辑与管理