Python中with用法详解

栏目: Python · 发布时间: 5年前

内容简介:断断续续玩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是可选的。其一般的执行过程是这样的:

  1. 执行EXPR,生成上下文管理器context_manager;
  2. 获取上下文管理器的 __exit()__ 方法,并保存起来用于之后的调用;
  3. 调用上下文管理器的 __enter__() 方法;如果使用了 as 子句,则将 __enter__() 方法的返回值赋值给 as 子句中的VAR;
  4. 执行BLOCK中的表达式;
  5. 不管是否执行过程中是否发生了异常,执行上下文管理器的 __exit__() 方法, __exit__() 方法负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句 break/continue/return ,则以 None 作为参数调用 __exit__(None, None, None) ;如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用 __exit__(exc_type, exc_value, exc_traceback)
  6. 出现异常时,如果 __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用法详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Joy of X

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》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具