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新手实现2048小游戏
Mar 31 Python
pycharm下打开、执行并调试scrapy爬虫程序的方法
Nov 29 Python
详解Python循环作用域与闭包
Mar 21 Python
利用Django模版生成树状结构实例代码
May 19 Python
Django中ORM外键和表的关系详解
May 20 Python
Python实现将字符串的首字母变为大写,其余都变为小写的方法
Jun 11 Python
使用PYTHON解析Wireshark的PCAP文件方法
Jul 23 Python
Python的几种主动结束程序方式
Nov 22 Python
Python偏函数Partial function使用方法实例详解
Jun 17 Python
Django封装交互接口代码
Jul 12 Python
使用py-spy解决scrapy卡死的问题方法
Sep 29 Python
python代数式括号有效性检验示例代码
Oct 04 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
第四节--构造函数和析构函数
2006/11/16 PHP
解决控件遮挡问题:关于有窗口元素和无窗口元素
2007/01/28 PHP
100多行PHP代码实现socks5代理服务器[2]
2016/05/05 PHP
php使用pthreads v3多线程实现抓取新浪新闻信息操作示例
2020/02/21 PHP
javascript引用对象的方法
2007/01/11 Javascript
js之WEB开发调试利器:Firebug 下载
2007/01/13 Javascript
JS打开图片另存为对话框实现代码
2012/12/26 Javascript
jquery如何实现锚点链接之间的平滑滚动
2013/12/02 Javascript
jQuery中unwrap()方法用法实例
2015/01/16 Javascript
jquery 标签 隔若干行加空白或者加虚线的方法
2016/12/07 Javascript
jQuery EasyUI 为Combo,Combobox添加清除值功能的实例
2017/04/13 jQuery
详解Vue 非父子组件通信方法(非Vuex)
2017/05/24 Javascript
jQuery实现一个简单的验证码功能
2017/06/26 jQuery
Angular 2.0+ 的数据绑定的实现示例
2017/08/09 Javascript
node文字生成图片的示例代码
2017/10/26 Javascript
微信小程序scroll-view组件实现滚动动画
2018/01/31 Javascript
几个你不知道的技巧助你写出更优雅的vue.js代码
2018/06/11 Javascript
ES6中let 和 const 的新特性
2018/09/03 Javascript
js实现删除json中指定的元素
2020/09/22 Javascript
python使用TensorFlow进行图像处理的方法
2018/02/28 Python
Python用csv写入文件_消除空余行的方法
2018/07/06 Python
使用python 将图片复制到系统剪贴中
2019/12/13 Python
tensorflow 实现打印pb模型的所有节点
2020/01/23 Python
Django 博客实现简单的全文搜索的示例代码
2020/02/17 Python
jupyter notebook 调用环境中的Keras或者pytorch教程
2020/04/14 Python
python爬虫利用代理池更换IP的方法步骤
2021/02/21 Python
任意一块网页内容实现“活”的背景(目前火狐浏览器专有)
2014/05/07 HTML / CSS
英国领先的家庭时尚品牌:Peacocks
2018/01/11 全球购物
如何理解委托
2012/01/06 面试题
机械系大学毕业生推荐信
2013/11/27 职场文书
2014年机关植树节活动方案
2014/02/27 职场文书
求职自荐信怎么写
2014/03/06 职场文书
年度考核表个人总结
2015/03/06 职场文书
工程竣工验收申请报告
2015/05/15 职场文书
2015年社区国庆节活动总结
2015/07/30 职场文书
人工智能深度学习OpenAI baselines的使用方法
2022/05/20 Python