内容简介:断断续续玩Python也有一段时间了,都是玩的很业余,写一些小的工具程序,基本上都是停留在能用的层面上。后来呢,自己想吧,不能总是这样学习吧,就寻思着把Python好好的、系统的、全面的学习一下,所以就买了几本书,想着这五一大过节的在家里安安静静的学习学习,陶冶陶冶,深造深造。可谁曾想,不看不知道,一看吓一大跳,这刚翻开没几页,就好几个模糊的知识点,而这篇将要总结的之前写一些Python小工具,读写文件都是这样搞的:基本也实现了读取文件的功能。但是有的时候,上述代码在运行的时候会抛出异常,导致无法关闭文件句
前言
断断续续玩 Python 也有一段时间了,都是玩的很业余,写一些小的 工具 程序,基本上都是停留在能用的层面上。后来呢,自己想吧,不能总是这样学习吧,就寻思着把Python好好的、系统的、全面的学习一下,所以就买了几本书,想着这五一大过节的在家里安安静静的学习学习,陶冶陶冶,深造深造。可谁曾想,不看不知道,一看吓一大跳,这刚翻开没几页,就好几个模糊的知识点,而这篇将要总结的 with
就是其中的一个。哎,不看了,撸串去~~~
抛出问题
之前写一些Python小工具,读写文件都是这样搞的:
#!/usr/bin/env python fileReader = open('students.txt', 'r') for row in fileReader: print(row.strip()) fileReader.close()
基本也实现了读取文件的功能。但是有的时候,上述代码在运行的时候会抛出异常,导致无法关闭文件句柄,这个时候,我就会加上异常处理程序,代码就改成了这样:
#!/usr/bin/env python try: fileReader = open('students.txt', 'r') for row in fileReader: print(row.strip()) except: print('Read file failed') finally: fileReader.close()
也还好,解决了抛出一大堆异常的问题。但是上述代码怎么看都有点累赘啰嗦的感觉。那怎么办?
解决问题
上面的代码虽然可以完成相应的功能,但是不简洁、很啰嗦,读起来也很麻烦。为了解决这种问题,从Python 2.5开始引入了 with
语句,一种与异常处理相关的功能。
with
语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。比如上面的代码,通过使用 with
语句改造,就变成了下面这个样子:
#!/usr/bin/env python with open('students.txt', 'r') as fileReader: for row in fileReader: print(row.strip())
可以看到,通过使用 with
语句重构,代码立马明朗了不少。这里虽然说了 with
怎么使用,但是并没有说到点上,没法让人真的明白 with
的原理。
深挖原理
为了更好的掌握 with
语句的用法,明白其内在的原理。这里就深挖一下 with
语句的原理,让大家知其然,更知其所以然。
要搞清楚 with
语句的原理,先要说一下下面这几个概念:
-
上下文管理协议(Context Management Protocol):包含方法
__enter__()
和__exit__()
,支持该协议的对象要实现这两个方法。 -
上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了
__enter__()
和__exit__()
方法。上下文管理器定义执行with
语句时要建立的运行时上下文,负责执行with
语句块上下文中的进入与退出操作。通常使用with
语句调用上下文管理器,也可以通过直接调用其方法来使用。
说完上面两个概念,我们再从 with
语句的常用表达式入手,一段基本的 with
表达式,其结构是这样的:
with EXPR as VAR: BLOCK
其中EXPR可以是任意表达式;as VAR是可选的。其一般的执行过程是这样的:
- 执行EXPR,生成上下文管理器context_manager;
-
获取上下文管理器的
__exit()__
方法,并保存起来用于之后的调用; -
调用上下文管理器的
__enter__()
方法;如果使用了as
子句,则将__enter__()
方法的返回值赋值给as
子句中的VAR; - 执行BLOCK中的表达式;
-
不管是否执行过程中是否发生了异常,执行上下文管理器的
__exit__()
方法,__exit__()
方法负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句break/continue/return
,则以None
作为参数调用__exit__(None, None, None)
;如果执行过程中出现异常,则使用sys.exc_info
得到的异常信息为参数调用__exit__(exc_type, exc_value, exc_traceback)
; -
出现异常时,如果
__exit__(type, value, traceback)
返回False,则会重新抛出异常,让with
之外的语句逻辑来处理异常,这也是通用做法;如果返回True,则忽略异常,不再对异常进行处理。
自定义上下文管理器
讲完了 with
语句的内在原理,接下来我们就可以按照这个原理,实现我们自己的上下文管理器。自定义的上下文管理器要实现上下文管理协议所需要的 __enter__()
和 __exit__()
两个方法:
#!/usr/bin/env python class DBManager(object): def __init__(self): pass def __enter__(self): print('__enter__') return self def __exit__(self, exc_type, exc_val, exc_tb): print('__exit__') return True def getInstance(): return DBManager() with getInstance() as dbManagerIns: print('with demo')
代码运行结果如下:
__enter__ with demo __exit__
这样我们就可以很轻松的自定义上下文管理器来对软件系统中的资源进行管理,比如数据库连接、共享资源的访问控制等。
总结
这篇文章通过实际的问题入手,分析问题,到最终的解决问题,环环相扣,通过通熟易懂的语言把Python中的 with
语句进行了比较全面的总结,希望对大家的Python学习之路有所帮助。
果冻想,认真玩技术的地方。
2019年5月3日,于内蒙古包头。
以上所述就是小编给大家介绍的《Python中with用法详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- SQLAlchemy框架用法详解
- Elasticsearch SQL 用法详解
- SQL中Merge用法详解
- Linux sort命令用法详解
- golang包time用法详解
- EventBus3.1用法详解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Joy of X
Niall Mansfield / UIT Cambridge Ltd. / 2010-7-1 / USD 14.95
Aimed at those new to the system seeking an overall understanding first, and written in a clear, uncomplicated style, this reprint of the much-cited 1993 classic describes the standard windowing syste......一起来看看 《The Joy of X》 这本书的介绍吧!