我们前面文章介绍了迭代器和可迭代对象,这次介绍python的上下文管理。在python中实现了__enter__和__exit__方法,即支持上下文管理器协议。上下文管理器就是支持上下文管理器协议的对象,它是为了with而生。当with语句在开始运行时,会在上下文管理器对象上调用 __enter__ 方法。with语句运行结束后,会在上下文管理器对象上调用 __exit__ 方法

with的语法:

with EXPR as VAR:
BLOCK

这是上面语法的伪代码:

mgr = (EXPR)
exit = type(mgr).__exit__ # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
try:
VAR = value # Only if "as VAR" is present
BLOCK
except:
# The exceptional case is handled here
exc = False
if not exit(mgr, *sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
exit(mgr, None, None, None)

1、生成上下文管理器mgr
2、如果没有发现__exit__, __enter__两个方法,解释器会抛出AttributeError异常
3、调用上下文管理器的 __enter__() 方法
4、如果语法里的as VAR没有写,那么 伪代码里的 VAR= 这部分也会同样被忽略
5、如果BLOCK中的代码正常结束,或者是通过break, continue ,return 来结束,__exit__()会使用三个None的参数来返回
6、如果执行过程中出现异常,则使用 sys.exc_info的异常信息为参数调用 __exit__(exc_type, exc_value, exc_traceback)

之前我们对文件的操作是这样的:

try:
f = open('filename')
except:
print("Unexpected error:", sys.exc_info()[0])
else:
print(f.readlines())
f.close()

现在有了with语句可以使代码更加简洁,减少编码量,下面的语句会在执行完后自动关闭文件(即使出现异常也会)。:

with open('example.info', 'r') as f:
print(f.readlines())

一个例子:

class TmpTest:
def __init__(self,filename):
self.filename=filename
def __enter__(self):
self.f = open(self.filename, 'r')
# return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close() test=TmpTest('file') with test as t:
print ('test result: {}'.format(t))

返回:

test result: None

这个例子里面__enter__没有返回,所以with语句里的"as t"到的是None,修改一下上面的例子:

class TmpTest:
def __init__(self,filename):
self.filename=filename
def __enter__(self):
self.f = open(self.filename, 'r')
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close() test=TmpTest('file') with test as t:
print ('test result: {}'.format(t))

返回:

test result: <_io.TextIOWrapper name='file' mode='r' encoding='cp936'>

如果在__init__或者__enter__中抛出异常,则不会进入到__exit__中:

class TmpTest:
def __init__(self,filename):
self.filename=filename
print("__init__")
raise ImportError
def __enter__(self):
self.f = open(self.filename, 'r')
print("__enter__")
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
print("__exit__")
self.f.close() test=TmpTest('file')
with test as t:
print ('test result: {}'.format(t))

返回:

__init__
Traceback (most recent call last):
File "D:/pythonScript/leetcode/leetcode.py", line 14, in <module>
test=TmpTest('file')
File "D:/pythonScript/leetcode/leetcode.py", line 5, in __init__
raise ImportError
ImportError

如果在__exit__中返回True,则不会产生异常:

class TmpTest:
def __init__(self,filename):
self.filename=filename
print("__init__") def __enter__(self):
self.f = open(self.filename, 'r')
print("__enter__")
return self.f def __exit__(self, exc_type, exc_val, exc_tb):
print("__exit__ {} ".format(exc_type))
self.f.close()
return True test=TmpTest('file')
with test as t:
print ('test result: {}'.format(t))
raise ImportError
print("no error")

返回:

__init__
__enter__
test result: <_io.TextIOWrapper name='file' mode='r' encoding='cp936'>
__exit__ <class 'ImportError'>
no error

参考: https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p03_make_objects_support_context_management_protocol.html?highlight=with
        https://docs.python.org/3/library/stdtypes.html#typecontextmanager
        https://www.python.org/dev/peps/pep-0343/

python中的__enter__ __exit__的更多相关文章

  1. python - 上下文管理协议(with + __enter__ + __exit__)

    上下文管理协议: with + __enter__ + __exit__ #上下问管理协议: #with + __enter__ + __exit__ class Test(): def __init ...

  2. python中那些双下划线开头得函数和变量--转载

    Python中下划线---完全解读     Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用'from module import *'导入 __xxx__ 系统定义名字 __x ...

  3. Python中异常(Exception)的总结

    Python中的异常处理 异常处理的语句结构 try: <statements> #运行try语句块,并试图捕获异常 except <name1>: <statement ...

  4. Python中With的用法

    在看Dive Into Python中有关描述文件读写那章节的时候,看到了有关with的用法,查阅下相关资料,记录下来,以备后用. 官方的reference上有关with statement是这样说的 ...

  5. python中with学习

    python中with是非常强大的一个管理器,我个人的理解就是,我们可以通过在我们的类里面自定义enter(self)和exit(self,err_type,err_value,err_tb)这两个内 ...

  6. Python中的上下文管理器和with语句

    Python2.5之后引入了上下文管理器(context manager),算是Python的黑魔法之一,它用于规定某个对象的使用范围.本文是针对于该功能的思考总结. 为什么需要上下文管理器? 首先, ...

  7. 整理一下python中with的用法

    ith替代了之前在python里使用try...finally来做清理工作的方法.基本形式如下: with expression [as variable]: with-block 当expressi ...

  8. python python中那些双下划线开头的那些函数都是干啥用用的

    1.写在前面 今天遇到了__slots__,,所以我就想了解下python中那些双下划线开头的那些函数都是干啥用用的,翻到了下面这篇博客,看着很全面,我只了解其中的一部分,还不敢乱下定义. 其实如果足 ...

  9. python中那些双下划线开头得函数和变量

    Python中下划线---完全解读     Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用’from module import *’导入 __xxx__ 系统定义名字 __x ...

随机推荐

  1. nodejs mongodb 查询要看的文章

    http://www.cnblogs.com/refactor/archive/2012/07/30/2591344.html 数组很大多数情况下可以这样理解:每一个元素都是整个键的值. db.use ...

  2. mysql新监语句需要前面加SET FOREIGN_KEY_CHECKS=0;

    SET FOREIGN_KEY_CHECKS=0; -- ------------------------------ Table structure for guestbook-- -------- ...

  3. js闭包的作用

    js闭包的用途详解 js闭包可以用在许多地方.它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中.具体怎么理解呢,各位看官请仔细看好下文   我们来看 ...

  4. 《Linux内核--分析Linux内核创建一个新进程的过程 》 20135311傅冬菁

    20135311傅冬菁 分析Linux内核创建一个新进程的过程 一.学习内容 进程控制块——PCB  task_struct数据结构 PCB task_struct中包含: 进程状态.进程打开的文件. ...

  5. 第三次spring冲刺1

    Not Check Out Check Out Done SPRINT GOAL: BETA-READY RELEASE 困难模式   DONE   修改已知bug   DONE   美化界面     ...

  6. Django-基本指令

    目录 Django基本指令 下载Django 创建Django项目 创建APP应用 启动Django项目 更新数据库表或字段 清空数据库数据 创建超级管理员 查看更多命令 Django基本指令 下载D ...

  7. Delphi中Form的position属性与代码自定义窗体位置

    通过Form的Position属性可设置窗体的初始位置,如选择DesktopCenter为桌面中心,ScreenCenter为屏幕中心,等等. 这个属性在很多时候简化了程序代码. 但是,如果设置了po ...

  8. php学习目录

    前面的话 前端工程师为什么要学习php?是因为招聘要求吗?这只是一方面 一开始,我对学习php是抵触的,毕竟javascript已经够自己喝一壶的了,再去学习php,可能让自己喝醉.但是,在学习jav ...

  9. BOM之navigator对象和用户代理检测

    前面的话 navigator对象现在已经成为识别客户端浏览器的事实标准,navigator对象是所有支持javascript的浏览器所共有的.本文将详细介绍navigator对象和用户代理检测 属性 ...

  10. FMDB基本操作

    1.以前使用数据库,因为一般就建立一张表,所以都是自己写代码创建,没用过fmdb,这次因为项目中涉及聊天模块,需要多张表格和数据库保存聊天记录 按照以前方法不好操作,就研究了下fmdb,发现确实挺方便 ...