1.上下文管理器是一个包装任意代码块的对象。上下文管理器保证进入上下文管理器时,每次执行代码的一致性;当退出上下文管理器时,相关的资源会被正确回收。
2.上下文管理器一定能够保证退出步骤的执行。如果进入上下文管理器,根据定义,一定会有退出步骤。即使内部代码抛出了异常,这点也成立。
3.上下文管理器的功能类似于try、except和finally关键字。通常,这也是一种封装需要被重复使用的try-except-finally结构的有效机制。
4.上下文管理器在Python 2.5中引入。
5.
a.从本质上讲,实际上是with语句对其后代码进行求值(在本例中,就是调用open函数)。该表达式会返回一个对象,该对象包含两个特殊方法:enter__和__exit。__enter__方法返回的结果会被赋给as关键字之后的变量。
b.在本例中,open对应的类就实现了__enter__和__exit__方法。
c.__enter__表示上文方法
d.__exit__表示下文方法,with语句执行完成会自动执行__exit__方法,即使出现异常也会执行该方法
e.__exit__方法带有3个位置参数(不包括self参数):一个异常类型、一个异常实例和一个回溯。如果没有异常,这3个参数全被设置成None,但如果在代码块内有异常发生,则参数被填充了。
with open('/path/to/filename', 'r') as my_file:
contents = my_file.read()
6.什么是上下文管理器
一个类只要实现了__enter__()和__exit__()这两个方法,通过该类创建的对象我们就称之为上下文管理器。
7.操作文件的上下文管理器的例子
a.正常处理文件
class MyOpen(object):
def __init__(self, file_name, file_mode):
self.file_name = file_name
self.file_mode = file_mode
def __enter__(self):
print('这是 __enter__ 函数')
self.file = open(self.file_name, self.file_mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
"""
:param exc_type:
:param exc_val:
:param exc_tb:
:return:
"""
print('这是 __exit__ 函数')
self.file.close()
with MyOpen('1.txt', 'r') as f:
file_data = f.read()
print(file_data)
'''
这是 __enter__ 函数
here is some text
这是 __exit__ 函数
'''
b. 处理文件时遇到异常
class MyOpen(object):
def __init__(self, file_name, file_mode):
self.file_name = file_name
self.file_mode = file_mode
def __enter__(self):
print('这是 __enter__ 函数')
self.file = open(self.file_name, self.file_mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
"""
:param exc_type:
:param exc_val:
:param exc_tb:
:return:
"""
print('这是 __exit__ 函数')
self.file.close()
with MyOpen('1.txt', 'r') as f:
file_data = f.read()
print(file_data)
raise Exception('error occur while handling file')
'''
这是 __enter__ 函数
here is some text
这是 __exit__ 函数
Traceback (most recent call last):
File "C:\Users\dyc\PycharmProjects\scripts\with和上下文管理器\上下文管理器.py", line 25, in <module>
raise Exception('error occur while handling file')
Exception: error occur while handling file
'''
8.何时应该编写上下文管理器
a.资源清理
b.避免重复
i.传播异常:__exit__方法可以向流程链上传播异常,这是通过返回False实现的。
class MyOpen(object):
def __init__(self, file_name, file_mode):
self.file_name = file_name
self.file_mode = file_mode
def __enter__(self):
print('这是 __enter__ 函数')
self.file = open(self.file_name, self.file_mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
"""
:param exc_type:
:param exc_val:
:param exc_tb:
:return:
"""
print('这是 __exit__ 函数')
self.file.close()
return False
with MyOpen('1.txt', 'r') as f:
file_data = f.read()
print(file_data)
raise Exception('error occur while handling file')
'''
Traceback (most recent call last):
File "C:\Users\dyc\PycharmProjects\scripts\with和上下文管理器\上下文管理器.py", line 26, in <module>
raise Exception('error occur while handling file')
Exception: error occur while handling file
这是 __enter__ 函数
here is some text
这是 __exit__ 函数
'''
ii.终止异常:__exit__方法可以终止它所接收的异常,这是通过返回True实现的。
class MyOpen(object):
def __init__(self, file_name, file_mode):
self.file_name = file_name
self.file_mode = file_mode
def __enter__(self):
print('这是 __enter__ 函数')
self.file = open(self.file_name, self.file_mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
"""
:param exc_type:
:param exc_val:
:param exc_tb:
:return:
"""
print('这是 __exit__ 函数')
self.file.close()
return True
with MyOpen('1.txt', 'r') as f:
file_data = f.read()
print(file_data)
raise Exception('error occur while handling file')
'''
这是 __enter__ 函数
here is some text
这是 __exit__ 函数
'''
c.处理特定异常类:这个就是在__exit__方法中对异常类型进行判断,可以仅处理某类异常,或实现其他功能。
d.基于属性的异常处理
9.使用contextlib简化上下文管理器的实现
a.yield之前的代码相当于__enter__函数的内容、
b.yield之后的代码相当于__exit__函数的内容
import contextlib
@contextlib.contextmanager
def handle_file(file_name):
print(f'open file: {file_name}')
yield
print(f'close file: {file_name}')
with handle_file('1.txt') as f:
print('process file')
'''
open file: 1.txt
process file
close file: 1.txt
'''