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 22 Python
基于python 爬虫爬到含空格的url的处理方法
May 11 Python
Python3.6简单反射操作示例
Jun 14 Python
python逆序打印各位数字的方法
Jun 25 Python
python得到电脑的开机时间方法
Oct 15 Python
浅谈python写入大量文件的问题
Nov 09 Python
python 使用装饰器并记录log的示例代码
Jul 12 Python
Python类中方法getitem和getattr详解
Aug 30 Python
基于Python+Appium实现京东双十一自动领金币功能
Oct 31 Python
通过python实现windows桌面截图代码实例
Jan 17 Python
完美解决Django2.0中models下的ForeignKey()问题
May 19 Python
python基础入门之字典和集合
Jun 13 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蜘蛛统计插件只要有mysql就可用
2010/10/12 PHP
PHP中防止直接访问或查看或下载config.php文件的方法
2012/07/07 PHP
PHP 数组遍历foreach语法结构及实例
2016/06/13 PHP
微信支付扫码支付php版
2016/07/22 PHP
php简单处理XML数据的方法示例
2017/05/19 PHP
laravel 判断查询数据库返回值的例子
2019/10/11 PHP
PHP8.0新功能之Match表达式的使用
2020/07/19 PHP
prototype Element学习笔记(篇二)
2008/10/26 Javascript
iframe自适应宽度、高度 ie6 7 8,firefox 3.86下测试通过
2010/07/29 Javascript
JS localStorage实现本地缓存的方法
2013/06/22 Javascript
jquery弹出框的用法示例(一)
2013/08/26 Javascript
基于JavaScript实现定时跳转到指定页面
2016/01/01 Javascript
jquery+json实现动态商品内容展示的方法
2016/01/14 Javascript
js简单实现调整网页字体大小的方法
2016/07/23 Javascript
JS仿JQuery选择器功能
2017/03/08 Javascript
JavaScript如何获取到导航条中HTTP信息
2017/10/10 Javascript
vue封装一个简单的div框选时间的组件的方法
2019/01/06 Javascript
vue实现手机端省市区区域选择
2019/09/27 Javascript
highcharts.js数据绑定方式代码实例
2019/11/13 Javascript
[01:15:56]2018DOTA2亚洲邀请赛3月30日 小组赛A组 TNC VS Newbee
2018/03/31 DOTA
使用pyinstaller打包PyQt4程序遇到的问题及解决方法
2019/06/24 Python
Win10下安装并使用tensorflow-gpu1.8.0+python3.6全过程分析(显卡MX250+CUDA9.0+cudnn)
2020/02/17 Python
python 实现 hive中类似 lateral view explode的功能示例
2020/05/18 Python
在pytorch中动态调整优化器的学习率方式
2020/06/24 Python
python中如何设置代码自动提示
2020/07/15 Python
HTML块级标签汇总(小篇)
2016/07/13 HTML / CSS
英国领先的新鲜松露和最好的松露产品供应商:TruffleHunter
2019/08/26 全球购物
美国最大的购物网站:Amazon.com(亚马逊美国)
2020/05/23 全球购物
办公室文员工作自我评价
2013/12/01 职场文书
西安交大自主招生自荐信
2014/01/27 职场文书
档案室主任岗位职责
2014/02/12 职场文书
会展策划与管理专业求职信
2014/06/09 职场文书
植树节口号
2014/06/21 职场文书
2015社区精神文明建设工作总结
2015/04/21 职场文书
CSS3 制作的书本翻页特效
2021/04/13 HTML / CSS
Django数据库(SQlite)基本入门使用教程
2022/07/07 Python