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检测lvs real server状态
Jan 22 Python
python设置检查点简单实现代码
Jul 01 Python
python 查找字符串是否存在实例详解
Jan 20 Python
python调用tcpdump抓包过滤的方法
Jul 18 Python
详解Python 正则表达式模块
Nov 05 Python
Python实现深度遍历和广度遍历的方法
Jan 22 Python
啥是佩奇?使用Python自动绘画小猪佩奇的代码实例
Feb 20 Python
详解Python字符串切片
May 20 Python
python实现从本地摄像头和网络摄像头截取图片功能
Jul 11 Python
python中栈的原理及实现方法示例
Nov 27 Python
Pytorch中Tensor与各种图像格式的相互转化详解
Dec 26 Python
基于Python实现股票收益率分析
Apr 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
给apache2.2加上mod_encoding模块後 php5.2.0 处理url出现bug
2007/04/12 PHP
一个完整的php文件上传类实例讲解
2015/10/27 PHP
PHP加密解密函数详解
2015/10/28 PHP
PHP7+Nginx的配置与安装教程详解
2016/05/10 PHP
PHP实现的猴王算法(猴子选大王)示例
2018/04/30 PHP
Laravel如何自定义command命令浅析
2019/03/23 PHP
php连接mysql数据库最简单的实现方法
2019/09/24 PHP
JavaScript OOP面向对象介绍
2010/12/02 Javascript
javascript高级学习笔记整理
2011/08/14 Javascript
jquery入门——事件机制之事件中的冒泡现象示例解释
2020/09/12 Javascript
jquery.idTabs 选项卡使用示例代码
2014/09/03 Javascript
基于JavaScript实现手机短信按钮倒计时(超简单)
2015/12/30 Javascript
js、jquery实现列表模糊搜索功能过程解析
2020/03/27 jQuery
[06:01]刀塔次级联赛top10第一期
2014/11/07 DOTA
[46:20]TFT vs Secret Supermajor小组赛C组 BO3 第二场 6.3
2018/06/04 DOTA
Python深度优先算法生成迷宫
2018/01/22 Python
python实现将读入的多维list转为一维list的方法
2018/06/28 Python
Python字符串的全排列算法实例详解
2019/01/07 Python
Python3从零开始搭建一个语音对话机器人的实现
2019/08/23 Python
python应用文件读取与登录注册功能
2019/09/23 Python
基于Python执行dos命令并获取输出的结果
2019/12/30 Python
Python使用py2neo操作图数据库neo4j的方法详解
2020/01/13 Python
使用keras实现孪生网络中的权值共享教程
2020/06/11 Python
Python高阶函数与装饰器函数的深入讲解
2020/11/10 Python
Python中Pyspider爬虫框架的基本使用详解
2021/01/27 Python
深入理解css中vertical-align属性
2017/04/18 HTML / CSS
幼儿园保教管理制度
2014/02/03 职场文书
《赠汪伦》教学反思
2014/04/12 职场文书
乡镇消防安全责任书
2014/07/23 职场文书
竞选班干部演讲稿100字
2014/08/20 职场文书
小学重阳节活动总结
2015/03/24 职场文书
尊师重教主题班会
2015/08/14 职场文书
2016年领导干部廉政承诺书
2016/03/24 职场文书
Pandas||过滤缺失数据||pd.dropna()函数的用法说明
2021/05/14 Python
写好Python代码的几条重要技巧
2021/05/21 Python
PostgreSQL通过oracle_fdw访问Oracle数据的实现步骤
2021/05/21 PostgreSQL