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中关于使用模块的基础知识
May 24 Python
Python3.7中安装openCV库的方法
Jul 11 Python
python实现将文件夹下面的不是以py文件结尾的文件都过滤掉的方法
Oct 21 Python
python+opencv实现霍夫变换检测直线
Oct 23 Python
Appium+python自动化怎么查看程序所占端口号和IP
Jun 14 Python
Django实现发送邮件功能
Jul 18 Python
Python动态导入模块:__import__、importlib、动态导入的使用场景实例分析
Mar 30 Python
Django模板标签{% for %}循环,获取制定条数据实例
May 14 Python
Python基于pip实现离线打包过程详解
May 15 Python
PyCharm常用配置和常用插件(小结)
Feb 06 Python
浅谈Python中对象是如何被调用的
Apr 06 Python
Python如何使用循环结构和分支结构
Apr 13 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
PHP 数据结构队列(SplQueue)和优先队列(SplPriorityQueue)简单使用实例
2015/05/12 PHP
详解PHP原生DOM对象操作XML的方法
2016/10/17 PHP
Thinkphp5行为使用方法汇总
2017/12/21 PHP
JQuery控制radio选中和不选中方法总结
2015/04/15 Javascript
jQuery实现鼠标跟随提示层效果代码(可显示文本,Div,Table,Html等)
2016/04/18 Javascript
基于js里调用函数时,函数名带括号和不带括号的区别
2016/07/28 Javascript
使用bootstrap-paginator.js 分页来进行ajax 异步分页请求示例
2017/03/09 Javascript
vue结合axios与后端进行ajax交互的方法
2018/07/06 Javascript
Vue.set() this.$set()引发的视图更新思考及注意事项
2018/08/30 Javascript
浅析微信扫码登录原理(小结)
2018/10/29 Javascript
微信小程序实现动态显示和隐藏某个控件功能示例
2018/12/14 Javascript
微信小程序通过一个json实现分享朋友圈图片
2019/09/03 Javascript
js实现多图和单图上传显示
2019/12/18 Javascript
JS实现打砖块游戏
2020/02/14 Javascript
vue-列表下详情的展开与折叠案例
2020/07/28 Javascript
python 运算符 供重载参考
2009/06/11 Python
Python中的进程分支fork和exec详解
2015/04/11 Python
利用Python实现简单的相似图片搜索的教程
2015/04/23 Python
Linux下为不同版本python安装第三方库
2016/08/31 Python
Python简单的制作图片验证码实例
2017/05/31 Python
python正则表达式面试题解答
2020/04/28 Python
python 使用cx-freeze打包程序的实现
2020/03/14 Python
Python3 中sorted() 函数的用法
2020/03/24 Python
python 浮点数四舍五入需要注意的地方
2020/08/18 Python
利用CSS3制作简单的3d半透明立方体图片展示
2017/03/25 HTML / CSS
德国高品质男装及配饰商城:Cultizm(Raw Denim原色牛仔裤)
2018/04/16 全球购物
Auguste The Label官网:澳大利亚一家精品女装时尚品牌
2020/06/14 全球购物
网上常见的一份Linux面试题(多项选择部分)
2015/02/07 面试题
生产厂长岗位职责
2014/02/21 职场文书
班级德育工作实施方案
2014/02/21 职场文书
化妆品店促销方案
2014/02/24 职场文书
教师自我鉴定范文
2014/03/20 职场文书
机关作风建设自查报告
2014/10/22 职场文书
2015年社区创卫工作总结
2015/04/21 职场文书
Python使用sql语句对mysql数据库多条件模糊查询的思路详解
2021/04/12 Python
Spring Cloud Gateway去掉url前缀
2021/07/15 Java/Android