python 上下文管理器详解
python的上下文管理器看了很多解释
vamei的python教程:
上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围。一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存)。它的语法形式是with…as…
python编程时光:
上下文表达式:with open(‘test.txt’) as f:
上下文管理器:open(‘test.txt’)
f 不是上下文管理器,应该是资源对象。
个人理解是对资源的一些操作!
上下文管理器的实现有两种方式,我用1/0这个例子来展示一下
第一种方式:
"""
一个类实现了 __enter__和__exit__的方法,这个类的实例就是一个上下文管理器
"""
import traceback
class Resource():
def __enter__(self):
"""
我们可以将一些资源初始化动作放在 __enter__
比如:数据库连接,打开文件
一般返回资源对象
"""
print('=== __enter__ ===')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""
__exit__ 包含三个参数:
exc_type 异常类型
exc_val 异常值
exc_tb 异常的错误栈信息
当没有异常时三个都是None
__exit__ 包含了异常捕捉和结束动作
"""
print(exc_type, exc_val, traceback.print_tb(exc_tb))
print('==== __exit__ ====')
return True
def zero_func(self, x):
print(1/x)
with Resource() as res:
"""
as 会把 __enter__ 返回值赋给 目标 res
如果我们让 __enter__ return 1,在这里我们print(res),会发现res的值是1,
如果我们在这里print(res),会发现先执行 __enter__ 再 执行__exit__
"""
res.zero_func(0)
"""
1/0 原本是会报错的,
但是这里如果没有在 __exit__ 打印错误信息的话,这里是不会有异常信息的
"""
第二种方式:
"""
通过contextlib 创建上下文管理器
"""
import traceback
import contextlib
# 使用修饰器 @contextlib.contextmanager
@contextlib.contextmanager
def zero_func(x):
# yield 之前的 都相当于 __enter__ 的内容
print('====== __enter__ =========')
try:
"""
yield 后面可以返回一个对象,相当于 __enter__ 的return
"""
yield
"""
yield 后面的内容相当于__exit__
"""
zero_parameter = 1/x
except Exception as exc:
# 处理异常
"""
如果使用traceback.print_exc()会返回一个空对象
错误信息的打印有可能出现在__exit__之后
"""
print(traceback.format_exc())
else:
# 没异常执行部分
print(zero_parameter)
finally:
# 结束
print('===== 结束 ====')
with zero_func(0) as x:
"""
这里print(x)会发现打印出一个None,这个其实是yield返回的空对象
这里还能看出来,print(x) 虽然在后面但是执行的时候是先执行
"""
print(x)
实战用两种上下文管理器实现打开文件:
第一种:
import traceback
class OpenFiles():
def __init__(self, filename, openway):
print('==== __init__ ====')
self.filename = filename
self.openway = openway
self.file_obj = None
def __enter__(self):
print('==== __enter__ ====')
self.file_obj = open(self.filename, self.openway)
return self.file_obj
def __exit__(self, exc_type, exc_val, exc_tb):
print(exc_type, exc_val, traceback.print_tb(exc_tb))
if self.file_obj:
self.file_obj.close()
print('==== __exit__ ====')
return True
with OpenFiles('text.txt', 'r') as res:
"""
如果test.txt不存在会报错,你可以用w创建一个,然后打开往里面写点东西,在改为r
python 中如果文件不存在,r r+会报错,w w+ a a+ 会创建
"""
print(res.readlines())
第二种:
import traceback
import contextlib
@contextlib.contextmanager
def open_file(filename, openway):
print('====== __enter__ =========')
try:
file_obj = open(filename, openway)
yield file_obj
print('====== __exit__ =========')
except Exception as exc:
print(traceback.format_exc())
else:
pass
finally:
file_obj.close()
with open_file('text.txt', 'r') as res:
print(res.readlines())
还没有评论,来说两句吧...