我们看一个with处理文件操作的实例:

with open('/etc/passwd') as f:
for line in f:
print(line)

这段代码的作用:打开一个文件,如果一切正常,把文件对象赋值给f,然后用迭代器遍历文件中每一行,当完成时,关闭文件;

而无论在这段代码的任何地方,如果发生异常,此时文件仍会被关闭。

with看起来如此简单,但是其背后还有一些工作要做,因为你不能对Python的任意对象使用with语句,它仅能工作于支持上下文管理协议(context management protocol)的对象。

也就是说,只有内建了“上下文管理”的对象可以和with一起工作,目前支持该协议的对象有:

  • file
  • decimal.Context
  • thread.LockType
  • threading.Lock
  • threading.RLock
  • threading.Condition
  • threading.Semaphore
  • threading.BoundedSemaphore

当with语句执行时,便执行上下文表达式(context_expr)来获得一个上下文管理器,上下文管理器的职责是提供一个上下文对象,用于在with语句块中处理细节:

一旦获得了上下文对象,就会调用它的__enter__()方法,将完成with语句块执行前的所有准备工作,如果with语句后面跟了as语句,则用__enter__()方法的返回值来赋值;

当with语句块结束时,无论是正常结束,还是由于异常,都会调用上下文对象的__exit__()方法,__exit__()方法有3个参数,如果with语句正常结束,三个参数全部都是 None;如果发生异常,三个参数的值分别等于调用sys.exc_info()函数返回的三个值:类型(异常类)、值(异常实例)和跟踪记录(traceback),相应的跟踪记录对象。

因为上下文管理器主要作用于共享资源,__enter__()和__exit__()方法干的基本是需要分配和释放资源的低层次工作,

比如:数据库连接、锁分配、信号量加/减、状态管理、文件打开/关闭、异常处理等。

知道了上面这些,我们就可以尝试在自定义类里面创建__enter__()和__exit__()方法,来配合with语句创建类实例了:

class A:
def __enter__(self):
print('__enter__() is called') def __exit__(self, e_t, e_v, t_b):
print('__exit__() is called') with A() as a:
print('got instance')

  输出:

另外python库中还有一个模块contextlib,使你不用构造含有__enter__, __exit__的类就可以使用with:

from __future__ import with_statement
from contextlib import contextmanager @contextmanager
def context():
print('entering the zone')
try:
yield
except Exception as e:
print('with an error %s'%e)
raise e
else:
print('with no error') with context():
print('----in context call------')

  输出:

Python之with语句原理的更多相关文章

  1. 谈谈 Python 程序的运行原理

    因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,谈谈 Python 程序的运行原理 这篇文章准确说是『Python 源码剖析』的 ...

  2. python 3 mysql 索引原理与慢查询优化

    python 3 mysql 索引原理与慢查询优化 一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最 ...

  3. Python 中生成器的原理

    生成器的使用 在 Python 中,如果一个函数定义的内部使用了 yield 关键字,那么在执行函数的时候返回的是一个生成器,而不是常规函数的返回值. 我们先来看一个常规函数的定义,下面的函数 f() ...

  4. python写红包的原理流程包含random,lambda其中的使用和见简单介绍

    Python写红包的原理流程 首先来说说要用到的知识点,第一个要说的是扩展包random,random模块一般用来生成一个随机数 今天要用到ramdom中unifrom的方法用于生成一个指定范围的随机 ...

  5. 理解python的with语句

    Python’s with statement provides a very convenient way of dealing with the situation where you have ...

  6. Python之with语句

    Python之with语句 在Python中,我们在打开文件的时候,为了代码的健壮性,通常要考虑一些异常情况,比如: try: ccfile = open('/path/data') content ...

  7. (Python )控制流语句if、for、while

    这一节,我们将学习Python的控制流语句,主要包括if.for.while.break.continue 和pass语句 1. If语句 if语句也许是我们最熟悉的语句.其使用方法如下: x=inp ...

  8. Python的with语句

    写过多线程程序的人肯定对各种锁很熟悉,尤其是下面这种代码 def lock_usage: lock.Lock() if(...) : lock.Unlock() return lock.Unlock( ...

  9. Python学习教程(learning Python)--3.3.4 Python的if-elif-else语句

    Python的if-elif-else语句用于多种条件判断后选择某个语句块执行.该语句可以利用一系列条件表达式进行检查,并在某个表达式为真的情况下执行相应的代码.需要注意的是,虽然if/elif/el ...

随机推荐

  1. phpcms v9取消验证码

    phpcms/modules/admin/index.php// $code = isset($_POST['code']) && trim($_POST['code']) ? tri ...

  2. HDU2037 今年暑假不AC

    解题思路:贪心问题,关键突破口是,先将节目的结束时间 从小到大排个序,然后依次判断后面一个节目的开始时间 是否大于或等于前一个符合条件的节目的结束时间.见代码: #include<cstdio& ...

  3. BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur 【tarjan】【DP】*

    BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur Description In an effort to better manage the grazing pat ...

  4. PHP----重置阿里云主机的密码

    登陆阿里云,找到你的服务器 点击更多,选择重置密码,根据提示就可以了 这个密码用于连接FTP工具和SSH工具

  5. Eclipse中添加web dynamic project【菜鸟学JAVA】

    很多eclipse版本是不能直接新建web dynamic project的,需要从网上找插件或更新.我的Eclipse的版本是(Version: 3.7.0) 比较方便的是在Help → Insta ...

  6. POJ1745动态规划

    Divisibility Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11622   Accepted: 4178 Des ...

  7. 关于不同应用程序存储IO类型的描述

    介绍 存储系统作为数据的载体,为前端的服务器和应用程序提供读写服务.存储阵列某种意义上来说,是对应用服务器提供数据服务的后端“服务器”.应用服务器对存 储系统发送数据的“读”和“写”的请求.然而,不同 ...

  8. Android多线程断点下载的代码流程解析

    Step 1:创建一个用来记录线程下载信息的表 创建数据库表,于是乎我们创建一个数据库的管理器类,继承SQLiteOpenHelper类 重写onCreate()与onUpgrade()方法 DBOp ...

  9. python list 列表

    1. 什么是列表 列表是一个可变的数据类型 列表由[]来表示, 每一项元素使用逗号隔开. 列表什么都能装. 能装对象的对象. 列表可以装大量的数据 2. 列表的索引和切片 列表和字符串一样. 也有索引 ...

  10. 如何使用 J2EE 连接器架构实现企业应用

    JCA (J2EE 连接器架构,javaConnector Architecture)是对J2EE标准集的重要补充.因为它注重的是将Java程序连接到非Java程序和软件包中间件的开发.连接器特指基于 ...