Python with用法:自动关闭文件进程


Posted in Python onJuly 10, 2019

实际上,Python 提供了 with 语句来管理资源关闭。比如可以把打开的文件放在 with 语句中,这样 with 语句就会帮我们自动关闭文件。

with 语句的语法格式如下:

with context expression [as target(s)]:
  with 代码块

在上面的语法格式中,context_expression 用于创建可自动关闭的资源。

例如,程序使用 with 语句来读取文件:

import codecs
# 使用with语句打开文件,该语句会负责关闭文件
with codecs.open("readlines_test.py", 'r', 'utf-8', buffering=True) as f:
  for line in f:
    print(line, end='')

程序也可以使用 with 语句来处理通过 fileinput.input 合并的多个文件,例如如下程序:

import fileinput
# 使用with语句打开文件,该语句会负责关闭文件
with fileinput.input(files=('test.txt', 'info.txt')) as f:
  for line in f:
    print(line, end='')

上面两个程序都使用了 with 语句来管理资源,因此它们都不需要显式关闭文件。

那么,with 语句的实现原理是什么?其实很简单,使用 with 语句管理的资源必须是一个实现上下文管理协议(context manage protocol)的类,这个类的对象可被称为上下文管理器。要实现上下文管理协议,必须实现如下两个方法:

  • context_manager.__enter__():进入上下文管理器自动调用的方法。该方法会在 with 代码块执行之前执行。如果 with 语句有 as子句,那么该方法的返回值会被赋值给 as 子句后的变量;该方法可以返回多个值,因此,在 as 子句后面也可以指定多个变量(多个变量必须由“()”括起来组成元组)。
  • context_manager.__exit__(exc_type, exc_value, exc_traceback):退出上下文管理器自动调用的方法。该方法会在 with 代码块执行之后执行。如果 with 代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为 None:如果 with 代码块因为异常而中止,程序也自动调用该方法,使用 sys.exc_info 得到的异常信息将作为调用该方法的参数。

通过上面的介绍不难发现,只要一个类实现了 __enter__() 和 __exit__(exc_type, exc_value, exc_traceback) 方法,程序就可以使用 with 语句来管理它;通过 __exit__() 方法的参数,即可判断出 with 代码块执行时是否遇到了异常。

换而言之,上面程序所用的文件对象、FileInput 对象,其实都实现了这两个方法,因此它们都可以接受 with 语句的管理。

下面我们自定义一个实现上下文管理协议的类,并使用 with 语句来管理它:

class FkResource:
  def __init__(self, tag):
    self.tag = tag
    print('构造器,初始化资源: %s' % tag)
  # 定义__enter__方法,with体之前的执行的方法
  def __enter__(self):
    print('[__enter__ %s]: ' % self.tag)
    # 该返回值将作为as子句中变量的值
    return 'fkit' # 可以返回任意类型的值
  # 定义__exit__方法,with体之后的执行的方法
  def __exit__(self, exc_type, exc_value, exc_traceback):
    print('[__exit__ %s]: ' % self.tag)
    # exc_traceback为None,代表没有异常
    if exc_traceback is None:
      print('没有异常时关闭资源')
    else:
      print('遇到异常时关闭资源')
      return False  # 可以省略,默认返回None也被看做是False
with FkResource('孙悟空') as dr:
  print(dr)
  print('[with代码块] 没有异常')
print('------------------------------')
with FkResource('白骨精'):
  print('[with代码块] 异常之前的代码')
  raise Exception
  print('[with代码块] ~~~~~~~~异常之后的代码')

上面程序定义了一个 FkResource 类,该类定义了 __enter__() 和 __exit__() 两个方法,因此该类的对象可以被 with 语句管理:

  • 程序在执行 with 代码块之前,会执行 __enter__() 方法,并将该方法的返回值赋值给 as 子句后的变量。
  • 程序在执行 with 代码块之后,会执行 __exit__() 方法,可以根据该方法的参数来判断 with 代码块是否有异常。

程序两次使用 with 语句管理 FkResource 对象。第一次,with 代码块没有出现异常。第二次,with 代码块出现了异常。大家可以看到,使用 with 语句两次对 FkResource 的管理略有差异(主要是在 __exit()__ 方法中略有差异)。

运行上面的程序,可以看到如下输出结果:

构造器,初始化资源: 孙悟空
[__enter__ 孙悟空]:
fkit
[with代码块] 没有异常
[__exit__ 孙悟空]:
没有异常时关闭资源
------------------------------
构造器,初始化资源: 白骨精
[__enter__ 白骨精]:
[with代码块] 异常之前的代码
[__exit__ 白骨精]:
遇到异常时关闭资源
Traceback (most recent call last):
 File "C:\Users\mengma\Desktop\1.py", line 26, in <module>
  raise Exception
Exception

从上面的输出结果来看,使用 with 语句管理资源,程序总可以在进入 with 代码块之前自动执行 __enter__() 方法,无论 with 代码块是否有异常,这个部分都是一样的,而且 __enter__() 方法的返回值被赋值给了 as 子句后的变量,如上面的 ① 号输出信息所示。

对于 with 代码块有异常和无异常这两种情况,此时主要通过 exit() 方法的参数进行判断,程序可针对 with 代码块是否有异常分别进行处理,如程序中代码所示。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python安装与使用redis的方法
Apr 19 Python
Python实现动态图解析、合成与倒放
Jan 18 Python
Python实现判断并移除列表指定位置元素的方法
Apr 13 Python
Python实现的多项式拟合功能示例【基于matplotlib】
May 15 Python
Pycharm 操作Django Model的简单运用方法
May 23 Python
Python图像处理之图像的读取、显示与保存操作【测试可用】
Jan 04 Python
对Python闭包与延迟绑定的方法详解
Jan 07 Python
Python中的Socket 与 ScoketServer 通信及遇到问题解决方法
Apr 01 Python
python如何给字典的键对应的值为字典项的字典赋值
Jul 05 Python
浅谈tensorflow使用张量时的一些注意点tf.concat,tf.reshape,tf.stack
Jun 23 Python
python3爬虫中多线程的优势总结
Nov 24 Python
全网最详细的PyCharm+Anaconda的安装过程图解
Jan 25 Python
Python中的几种矩阵乘法(小结)
Jul 10 #Python
用Python实现最速下降法求极值的方法
Jul 10 #Python
python networkx 根据图的权重画图实现
Jul 10 #Python
python networkx 包绘制复杂网络关系图的实现
Jul 10 #Python
python卸载后再次安装遇到的问题解决
Jul 10 #Python
Python求离散序列导数的示例
Jul 10 #Python
Python Matplotlib 基于networkx画关系网络图
Jul 10 #Python
You might like
url decode problem 解决方法
2011/12/26 PHP
PHP笔记之:基于面向对象设计的详解
2013/05/14 PHP
php四种定界符详解
2017/02/16 PHP
php面向对象重点知识分享
2019/09/27 PHP
新闻内页-JS分页
2006/06/07 Javascript
用倒置滤镜把div倒置,再把table倒置。
2007/07/31 Javascript
jquery获取特定name所有选中的checkbox,支持IE9标准模式
2013/03/18 Javascript
JS判断元素是否在数组内的实现代码
2016/03/30 Javascript
Node.js 应用跑得更快 10 个技巧
2016/04/03 Javascript
jQuery1.9+中删除了live以后的替代方法
2016/06/17 Javascript
浅谈jQuery hover(over, out)事件函数
2016/12/03 Javascript
完美解决node.js中使用https请求报CERT_UNTRUSTED的问题
2017/01/08 Javascript
vue 粒子特效的示例代码
2017/09/19 Javascript
详解vue项目打包后通过百度的BAE发布到网上的流程
2018/03/05 Javascript
详解webpack打包时排除其中一个css、js文件或单独打包一个css、js文件(两种方法)
2018/10/26 Javascript
layui监听select变化,以及设置radio选中的方法
2019/09/24 Javascript
快速解决vue2+vue-cli3项目ie兼容的问题
2020/11/17 Vue.js
vue $router和$route的区别详解
2020/12/02 Vue.js
在Linux系统上通过uWSGI配置Nginx+Python环境的教程
2015/12/25 Python
python排序函数sort()与sorted()的区别
2018/09/18 Python
Python中的list与tuple集合区别解析
2019/10/12 Python
如何使用python的ctypes调用医保中心的dll动态库下载医保中心的账单
2020/05/24 Python
pip已经安装好第三方库但pycharm中import时还是标红的解决方案
2020/10/09 Python
Python用户自定义异常的实现
2020/12/25 Python
关于解决iframe标签嵌套问题的解决方法
2020/03/04 HTML / CSS
The Kooples美国官方网站:为情侣提供的法国当代时尚品牌
2019/01/03 全球购物
将时尚融入珠宝:Adornmonde
2019/10/17 全球购物
J2EE面试题
2016/03/14 面试题
人力资源管理毕业生自荐信
2013/11/21 职场文书
大学生村官承诺书
2014/03/28 职场文书
党员教师个人对照检查材料(群众路线)
2014/09/26 职场文书
2014年语文教研组工作总结
2014/12/06 职场文书
新教师个人总结
2015/02/06 职场文书
天那边观后感
2015/06/09 职场文书
学校2016年圣诞节活动总结
2016/03/31 职场文书
CSS3 制作的书本翻页特效
2021/04/13 HTML / CSS