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字典实现简单的三级菜单(实例讲解)
Jul 31 Python
Python实现的概率分布运算操作示例
Aug 14 Python
Python实现图片转字符画的示例
Aug 22 Python
分享一个简单的python读写文件脚本
Nov 25 Python
详解python 爬取12306验证码
May 10 Python
Python流行ORM框架sqlalchemy安装与使用教程
Jun 04 Python
python频繁写入文件时提速的方法
Jun 26 Python
Python Numpy计算各类距离的方法
Jul 05 Python
浅谈python的elementtree模块处理中文注意事项
Mar 06 Python
Python爬虫工具requests-html使用解析
Apr 29 Python
用python写一个带有gui界面的密码生成器
Nov 06 Python
Python文件名匹配与文件复制的实现
Dec 11 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中session与cookie的比较
2015/01/27 PHP
gearman管理工具GearmanManager的安装与php使用方法示例
2020/02/27 PHP
JS常见问题整理(持续更新)
2013/08/06 Javascript
jQuery实现列表的全选功能
2015/03/18 Javascript
javascript基于prototype实现类似OOP继承的方法
2015/12/16 Javascript
给angular加上动画效遇到的问题总结
2016/02/17 Javascript
JavaScript实现页面跳转的方式汇总
2016/05/16 Javascript
关于session和cookie的简单理解
2016/06/08 Javascript
AngularJS 执行流程详细介绍
2016/08/18 Javascript
微信小程序  TLS 版本必须大于等于1.2问题解决
2017/02/22 Javascript
详解如何用webpack打包一个网站应用项目
2017/07/12 Javascript
js Date()日期函数浏览器兼容问题解决方法
2017/09/12 Javascript
vue: WebStorm设置快速编译运行的方法
2018/10/18 Javascript
微信小程序实现两个页面传值的方法分析
2018/12/11 Javascript
详解webpack编译速度提升之DllPlugin
2019/02/05 Javascript
JS动态显示倒计时效果
2019/12/12 Javascript
Vue如何使用混合Mixins和插件开发详解
2020/02/05 Javascript
Element的el-tree控件后台数据结构的生成以及方法的抽取
2020/03/05 Javascript
[51:26]VP vs VG 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python验证码识别处理实例
2015/12/28 Python
python SSH模块登录,远程机执行shell命令实例解析
2018/01/12 Python
python中使用iterrows()对dataframe进行遍历的实例
2018/06/09 Python
pycharm修改界面主题颜色的方法
2019/01/17 Python
Python docx库用法示例分析
2019/02/16 Python
使用python爬取抖音视频列表信息
2019/07/15 Python
linux环境下安装python虚拟环境及注意事项
2020/01/07 Python
Tensorflow矩阵运算实例(矩阵相乘,点乘,行/列累加)
2020/02/05 Python
HTML5本地存储之Database Storage应用介绍
2013/01/06 HTML / CSS
中国排名第一的外贸销售网站:LightInTheBox.com(兰亭集势)
2016/10/28 全球购物
通信工程毕业生求职信
2013/11/16 职场文书
写求职信要注意什么问题
2014/04/12 职场文书
人事行政专员岗位职责
2014/07/23 职场文书
2014优秀党员事迹材料
2014/08/14 职场文书
交通局领导班子群众路线教育实践活动对照检查材料思想汇报
2014/10/09 职场文书
2014年财务工作总结范文
2014/11/11 职场文书
律政俏佳人观后感
2015/06/09 职场文书