Python with语句上下文管理器两种实现方法分析


Posted in Python onFebruary 09, 2018

本文实例讲述了Python with语句上下文管理器。分享给大家供大家参考,具体如下:

在编程中会经常碰到这种情况:有一个特殊的语句块,在执行这个语句块之前需要先执行一些准备动作;当语句块执行完成后,需要继续执行一些收尾动作。例如,文件读写后需要关闭,数据库读写完毕需要关闭连接,资源的加锁和解锁等情况。

对于这种情况python提供了上下文管理器(Context Manager)的概念,可以通过上下文管理器来定义/控制代码块执行前的准备动作,以及执行后的收尾动作。

一、为何使用上下文管理器

1、不使用上下文管理器的情况

通过try...finally语句执行异常处理和关闭句柄的动作。

logger = open("log.txt", "w")
try:
logger.write('Hello ')

logger.write('World')
finally:

logger.close()
print logger.closed

2、使用上下文管理器

默认文件Python的内置file类型是支持上下文管理协议的。
使用上下文管理器with使得依据精简了很多。

with open("log.txt", "w") as logger:
logger.write('Hello ')

logger.write('World')
print logger.closed

二、实现上下文管理器实现上下文管理器有两种方式实现。方法一:类实现__enter__和__exit__方法。方法二:contextlib模块装饰器和生成器实现。

下面我们通过两种方法分别实现一个自定义的上下文管理器。

1、方法一:通过类实现__enter__和__exit__方法

class File(object):
 def __init__(self, file_name, method):
  self.file_obj = open(file_name, method)
 def __enter__(self):
  return self.file_obj
 def __exit__(self, type, value, traceback):
  self.file_obj.close()
with File('demo.txt', 'w') as opened_file:
 opened_file.write('Hola!')

实现__enter__和__exit__方法后,就能通过with语句进行上下文管理。

a、底层都发生了什么?

1、with语句先暂存了File类的__exit__方法,然后它调用File类的__enter__方法。
2、__enter__方法打开文件并返回给with语句,打开的文件句柄被传递给opened_file参数。
3、with语句调用之前暂存的__exit__方法,__exit__方法关闭了文件。

b、异常处理

关于异常处理,with语句会采取哪些步骤。

1. 它把异常的type,value和traceback传递给__exit__方法
2. 它让__exit__方法来处理异常
3. 如果__exit__返回的是True,那么这个异常就被忽略。
4. 如果__exit__返回的是True以外的任何东西,那么这个异常将被with语句抛出。

异常抛出

#异常抛出,_exit__返回的是True以外的任何东西,那么这个异常将被with语句抛出
class File(object):
 def __init__(self, file_name, method):
  self.file_obj = open(file_name, method)
 def __enter__(self):
  return self.file_obj
 def __exit__(self, type, value, traceback):
  self.file_obj.close()
  print "type:",type
  print "value:",value
  print "traceback:",traceback
with File('demo.txt', 'w') as opened_file:
 opened_file.undefined_function('Hola!')
#output================================================
# type: <type 'exceptions.AttributeError'>
# value: 'file' object has no attribute 'undefined_function'
# traceback: <traceback object at 0x000000000262D9C8>
#  opened_file.undefined_function('Hola!')
# AttributeError: 'file' object has no attribute 'undefined_function'

异常忽略:

#异常忽略,__exit__返回的是True,那么这个异常就被忽略。
class File(object):
 def __init__(self, file_name, method):
  self.file_obj = open(file_name, method)
 def __enter__(self):
  return self.file_obj
 def __exit__(self, exception_type, exception_value, traceback):
  print("Exception has been handled")
  self.file_obj.close()
  return True
with File('demo.txt', 'w') as opened_file:
 opened_file.undefined_function('Hola!')
# output==================================
# Exception has been handled

2、方法二:contextlib模块装饰器和生成器实现

这种方式实现更优雅,我个人更喜欢这种方式。

yield之前的代码由__enter__方法执行,yield之后的代码由__exit__方法执行。本质上还是__enter____exit__方法。

# coding:utf-8
import contextlib
@contextlib.contextmanager
def myopen(filename, mode):
 f = open(filename, mode)
 try:
  yield f.readlines()
 except Exception as e:
  print e
 finally:
  f.close()
if __name__ == '__main__':
 with myopen(r'c:\ip2.txt', 'r') as f:
  for line in f:
   print line

3、with语句上多个下文关联

直接通过一个with语句打开多个上下文,即可同时使用多个上下文变量,而不必需嵌套使用with语句。

class File(object):
 def __init__(self, file_name, method):
  self.file_obj = open(file_name, method)
 def __enter__(self):
  return self.file_obj
 def __exit__(self, exception_type, exception_value, traceback):
  self.file_obj.close()
  return True
with File('demo.txt', 'w') as f1,File('demo.txt','w') as f2:
 print f1,f2
# Output============================# <open file 'demo.txt', mode 'w' at 0x000000000263D150> <open file 'demo.txt', mode 'w' at 0x000000000263D1E0>

更多关于Python相关内容可查看本站专题:《Python数据结构与算法教程》、《Python Socket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python Web框架Flask下网站开发入门实例
Feb 08 Python
Python安装第三方库及常见问题处理方法汇总
Sep 13 Python
Anaconda多环境多版本python配置操作方法
Sep 12 Python
python里使用正则表达式的组嵌套实例详解
Oct 24 Python
python修改txt文件中的某一项方法
Dec 29 Python
Python CVXOPT模块安装及使用解析
Aug 01 Python
Python 用三行代码提取PDF表格数据
Oct 13 Python
使用 Python 合并多个格式一致的 Excel 文件(推荐)
Dec 09 Python
Python sorted对list和dict排序
Jun 09 Python
Python爬虫小例子——爬取51job发布的工作职位
Jul 10 Python
python字典按照value排序方法
Dec 28 Python
python使用openpyxl库读写Excel表格的方法(增删改查操作)
May 02 Python
Python遍历pandas数据方法总结
Feb 09 #Python
python中的闭包函数
Feb 09 #Python
基于Python socket的端口扫描程序实例代码
Feb 09 #Python
利用python 更新ssh 远程代码 操作远程服务器的实现代码
Feb 08 #Python
Tensorflow 利用tf.contrib.learn建立输入函数的方法
Feb 08 #Python
django数据库migrate失败的解决方法解析
Feb 08 #Python
python使用锁访问共享变量实例解析
Feb 08 #Python
You might like
php获取参数的几种方法总结
2014/02/18 PHP
PHP中Session引起的脚本阻塞问题解决办法
2014/04/08 PHP
php实现将数组转换为XML的方法
2015/03/09 PHP
php相对当前文件include其它文件的方法
2015/03/13 PHP
thinkPHP5.0框架安装教程
2017/03/25 PHP
PHP使用finfo_file()函数检测上传图片类型的实现方法
2017/04/18 PHP
php设计模式之备忘模式分析【星际争霸游戏案例】
2020/03/24 PHP
Thinkphp 框架扩展之应用模式实现方法分析
2020/04/27 PHP
javascript实现的HashMap类代码
2014/06/27 Javascript
jQuery函数map()和each()介绍及异同点分析
2014/11/08 Javascript
详解JavaScript中setSeconds()方法的使用
2015/06/11 Javascript
Javascript 高阶函数使用介绍
2015/06/15 Javascript
JS表格组件BootstrapTable行内编辑解决方案x-editable
2016/09/01 Javascript
ionic2自定义cordova插件开发以及使用(Android)
2017/06/19 Javascript
基于jQuery实现的单行公告活动轮播效果
2017/08/23 jQuery
Angular中点击li标签实现更改颜色的核心代码
2017/12/08 Javascript
9种使用Chrome Firefox 自带调试工具调试javascript技巧
2017/12/22 Javascript
vue2.0$nextTick监听数据渲染完成之后的回调函数方法
2018/09/11 Javascript
vue+高德地图写地图选址组件的方法
2019/05/18 Javascript
python实现搜索指定目录下文件及文件内搜索指定关键词的方法
2015/06/28 Python
使用Python爬取最好大学网大学排名
2018/02/24 Python
pygame游戏之旅 添加碰撞效果的方法
2018/11/20 Python
Python用字典构建多级菜单功能
2019/07/11 Python
Python实现的企业粉丝抽奖功能示例
2019/07/26 Python
Python连接Hadoop数据中遇到的各种坑(汇总)
2020/04/14 Python
python中的测试框架
2020/11/13 Python
python实现图像高斯金字塔的示例代码
2020/12/11 Python
python+selenium实现12306模拟登录的步骤
2021/01/21 Python
广告设计专业自荐信范文
2013/11/14 职场文书
2014年技术工作总结范文
2014/11/20 职场文书
劳动争议和解协议书范本
2014/11/20 职场文书
婚礼女方父母答谢词
2015/01/04 职场文书
2015年语文教师工作总结
2015/05/25 职场文书
Keras在mnist上的CNN实践,并且自定义loss函数曲线图操作
2021/05/25 Python
java中为什么说子类的构造方法默认访问的是父类的无参构造方法
2022/04/13 Java/Android
table不让td文字溢出操作方法
2022/12/24 HTML / CSS