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

实际上,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 代码块是否有异常分别进行处理,如程序中代码所示。

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

(0)

相关推荐

  • 在python中使用with打开多个文件的方法

    虽然初恋是java, 可是最近是越来越喜欢python, 所以决定追根溯源好好了解下python的原理,架构等等.小脑袋瓜不太好使,只能记录下慢慢进步吧 使用with打开文件的好处不多说,这里记录一下如果要打开多个文件,该怎么书写简捷的代码. 场景是同时打开三个文件,文件行数一样,程序实现每个文件依次读取一行,同时输出. 首先来一种比较容易想到的写法,如下一样嵌套: with open('file1') as f1: with open('file2') as f2: with open('fi

  • python语言中with as的用法使用详解

    With语句是什么? 有一些任务,可能事先需要设置,事后做清理工作.对于这种场景,Python的with语句提供了一种非常方便的处理方式.一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄. 如果不用with语句,代码如下: file = open("/tmp/foo.txt") data = file.read() file.close() 这里有两个问题.一是可能忘记关闭文件句柄:二是文件读取数据发生异常,没有进行任何处理.下面是处理异常的加强版本

  • 简单介绍Python中的try和finally和with方法

    用 Python 做一件很平常的事情: 打开文件, 逐行读入, 最后关掉文件; 进一步的需求是, 这也许是程序中一个可选的功能, 如果有任何问题, 比如文件无法打开, 或是读取出错, 那么在函数内需要捕获所有异常, 输出一行警告并退出. 代码可能一开始看起来是这样的 def read_file(): try: f = open('yui', 'r') print ''.join(f.readlines()) except: print 'error occurs while reading fi

  • Python ValueError: invalid literal for int() with base 10 实用解决方法

    今天在写爬虫程序的时候由于要翻页,做除法分页的时候出现了 复制代码 代码如下: totalCount = '100' totalPage = int(totalCount)/20 ValueError: invalid literal for int() with base 10的错误 网上同样的错误有人建议用round(float("1.0″)),但是解决不了我这个问题,round(float("1.0″))是用于解决浮点数转换为整形数的, 而我这个则是因为原字符串转换为整形后做除法

  • Python 中的with关键字使用详解

    在 Python 2.5 中, with 关键字被加入.它将常用的 try ... except ... finally ... 模式很方便的被复用.看一个最经典的例子: with open('file.txt') as f: content = f.read() 在这段代码中,无论 with 中的代码块在执行的过程中发生任何情况,文件最终都会被关闭.如果代码块在执行的过程中发生了一个异常,那么在这个异常被抛出前,程序会先将被打开的文件关闭. 再看另外一个例子. 在发起一个数据库事务请求的时候,

  • Python 的 with 语句详解

    一.简介 with是从Python 2.5 引入的一个新的语法,更准确的说,是一种上下文的管理协议,用于简化try-except-finally的处理流程.with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常.对于一些需要预先设置,事后要清理的一些任务,with提供了一种非常方便的表达. with的基本语法如下,EXPR是一个任意表达式,VAR是一个单一的变量(可以是tuple),"as VAR"是可选的. 复制代码 代码如下: with EXPR as

  • 详解Python with/as使用说明

    with/as 使用open打开过文件的对with/as都已经非常熟悉,其实with/as是对try/finally的一种替代方案. 当某个对象支持一种称为"环境管理协议"的协议时,就会通过环境管理器来自动执行某些善后清理工作,就像finally一样:不管中途是否发生异常,最终都会执行某些清理操作. 用法: with expression [as var]: with_block_code 当expression返回的对象是支持环境管理协议的时候,就可以使用with.as var是可选

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

    实际上,Python 提供了 with 语句来管理资源关闭.比如可以把打开的文件放在 with 语句中,这样 with 语句就会帮我们自动关闭文件. with 语句的语法格式如下: with context expression [as target(s)]: with 代码块 在上面的语法格式中,context_expression 用于创建可自动关闭的资源. 例如,程序使用 with 语句来读取文件: import codecs # 使用with语句打开文件,该语句会负责关闭文件 with

  • python 读写、创建 文件的方法(必看)

    python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目录名:os.listdir() 函数用来删除一个文件:os.remove() 删除多个目录:os.removedirs(r"c:\python") 检验给出的路径是否是一个文件:os.path.isfile() 检验给出的路径是否是一个目录:os.path.isdir() 判断是否是绝对路

  • python中os操作文件及文件路径实例汇总

    本文实例讲述了python中os操作文件及文件路径的方法.分享给大家供大家参考.具体分析如下: python获取文件上一级目录:取文件所在目录的上一级目录 复制代码 代码如下: os.path.abspath(os.path.join(os.path.dirname('settings.py'),os.path.pardir)) os.path.pardir是父目录,os.path.abspath是绝对路径 举例具体看一下输出: 复制代码 代码如下: print os.path.dirname(

  • python多线程用法实例详解

    本文实例分析了python多线程用法.分享给大家供大家参考.具体如下: 今天在学习尝试学习python多线程的时候,突然发现自己一直对super的用法不是很清楚,所以先总结一些遇到的问题.当我尝试编写下面的代码的时候: 复制代码 代码如下: class A():     def __init__( self ):         print "A" class B( A ):     def __init__( self ):         super( B, self ).__in

  • Python基于正则表达式实现文件内容替换的方法

    本文实例讲述了Python基于正则表达式实现文件内容替换的方法.分享给大家供大家参考,具体如下: 最近因为有一个项目需要从普通的服务器移植到SAE,而SAE的thinkphp文件结构和本地测试的有出入,需要把一些html和js的引用路径改成SAE的形式,为了不手工改,特地速成了一下Python的正则表达式和文件操作.主要要求是将某目录下的html和js里面的几个路径变量分别更改成相应的形式,匹配文件名的时候用了正则 import os import re #all file in the dir

  • Python随机数用法实例详解【基于random模块】

    本文实例讲述了Python随机数用法.分享给大家供大家参考,具体如下: 1. random.seed(int) 给随机数对象一个种子值,用于产生随机序列. 对于同一个种子值的输入,之后产生的随机数序列也一样. 通常是把时间秒数等变化值作为种子值,达到每次运行产生的随机系列都不一样 seed() 省略参数,意味着使用当前系统时间生成随机数 random.seed(10) print random.random() #0.57140259469 random.seed(10) print rando

  • Python进程间通信用法实例

    本文实例讲述了Python进程间通信用法.分享给大家供大家参考.具体如下: #!/usr/bin/env python # -*- coding=utf-8 -*- import multiprocessing def counsumer(input_q): while True: item = input_q.get() #处理项目 print item #此处替换为有用的工作 #发出信号通知任务完成 input_q.task_done() def producer(sequence,outp

  • python实现实时监控文件的方法

    在业务稳定性要求比较高的情况下,运维为能及时发现问题,有时需要对应用程序的日志进行实时分析,当符合某个条件时就立刻报警,而不是被动等待出问题后去解决,比如要监控nginx的$request_time和$upstream_response_time时间,分析出最耗时的请求,然后去改进代码,这时就要对日志进行实时分析了,发现时间长的语句就要报警出来,提醒开发人员要关注,当然这是其中一个应用场景,通过这种监控方式还可以应用到任何需要判断或分析文件的地方,所以今天我们就来看看如何用python实现实时监

  • Python全局变量用法实例分析

    本文实例讲述了Python全局变量用法.分享给大家供大家参考,具体如下: 全局变量不符合参数传递的精神,所以,平时我很少使用,除非定义常量.今天有同事问一个关于全局变量的问题,才发现其中原来还有门道. 程序大致是这样的: CONSTANT = 0 def modifyConstant() : print CONSTANT CONSTANT += 1 return if __name__ == '__main__' : modifyConstant() print CONSTANT 运行结果如下:

  • Python使用Supervisor来管理进程的方法

    本文实例讲述了Python使用Supervisor来管理进程的方法.分享给大家供大家参考.具体分析如下: Supervisor可以启动.停止.重启*nix系统中的程序.也可以重启崩溃的程序. supervisord的一个守护进程,用于将指定的进程当做子进程来运行. supervisorctl是一个客户端程序,可以查看日志并通过统一的会话来控制进程. 看例子: 我们写了一个py脚本,用于往log文件中记录一条当前的时间. root@ubuntu:/home/zoer# cat daemon.py

随机推荐