1.模块简介
上下文管理器就是允许你可以自动地开始和结束一些事情。最常用的场景就是打开文件、写入内容、关闭文件了。当你使用with语句时,python会自动创建一个上下文管理器
with open(r'new.txt') as f:
f.write('hello world')
上下文管理器背后的工作机制是采用python的方法:enter和exit。
2.模块使用
2.1 自定义创建一个上下文管理器类
import sqlite3
class Dao(object):
def __init__(self, db):
self.db = db
def __enter__(self):
self.connect = sqlite3.connect(self.db)
return self.connect
def __exit__(self, exc_type, exc_val, exc_tb):
self.connect.close()
if __name__ == '__main__':
db = 'test/test.db'
with Dao(db) as dao:
dao.cursor()
这里创建一个数据库操作的类,传入数据库路径后,将自动执行__enter__()方法,为我们创建一个数据库对象。当结束数据库操作准备退出时, exit()会自动执行关闭这个链接
2.2 利用contextlib创建一个上下文管理器
from contextlib import contextmanager
@contextmanager
def file_handle(file_path):
global file_object
try:
file_object = open(file_path, "w")
yield file_object
except:
print("file error")
finally:
print("colse file")
file_object.close()
if __name__ == "__main__":
with file_handle("test_123.txt") as f:
f.write("上下文管理器")
3 其他类
3.1 colsing类
一旦代码运行完毕,该类就会将事件关闭。
from contextlib import closing
import requests
with closing(requests.get(r'https://www.baidu.com/')) as data:
print(data.status_code)
这里在closing中访问百度首页, 当访问结束后,指向该页面的句柄就会自动关闭
3.2 suppress类
suppress类的作用主要是为了禁止任意数目的异常。比如我们想要忽略FileNotFoundError异常,普通的with语句就会报错
with open(r'1.txt') as f:
print(f.read())
result:
Traceback (most recent call last):
File "D:/ywb/123.py", line 1, in <module>
with open(r'1.txt') as f:
FileNotFoundError: [Errno 2] No such file or directory: '1.txt'
如果要使得程序忽略这个异常,可以按照如下的方式进行:
from contextlib import suppress
with suppress(FileNotFoundError):
with open(r"1.txt") as f:
print(f.read())
print('end......')
result:
end......
3.3 redirect_stdout类
该类主要是用于标准输出重定向,举例如下:
运行前:
代码;
from contextlib import redirect_stdout
path = "test.txt"
with open(path,"w") as fobj:
with redirect_stdout(fobj):
print(redirect_stdout)
运行后:
3.4 redirect_stderr类
该类主要是用于标准错误重定向,举例如下:
运行前:
代码;
from contextlib import redirect_stderr
path = "test2.txt"
with open(path,"w") as fobj:
with redirect_stderr(fobj):
print(redirect_stderr)
运行后:
3.5 ExitStack类
from contextlib import ExitStack
filenames = ["1.txt", "2.txt"]
with ExitStack as stack:
for filename in filenames:
with open(filename) as f:
file_objects = stack.enter_context(f)
3.6 可重用的上下文管理器
大部分情况下创建的上下文管理器之只能使用一次,没法进行多次调用。
from contextlib import contextmanager
@contextmanager
def context():
print("yield")
yield
print("上下文管理器已存在")
context1 = context()
with context1:
pass
print("============================")
with context1:
pass
result:
yield
上下文管理器已存在
============================
Traceback (most recent call last):
File "D:/ywb/123.py", line 15, in <module>
with context1:
File "D:\ThsSoftware\Python_ths\ths\lib\contextlib.py", line 111, in __enter__
del self.args, self.kwds, self.func
AttributeError: args
Process finished with exit code 1
如果我们需要让其成为可以重用的上下文管理器,需要结合redirect_stdout进行操作
from contextlib import redirect_stdout
from io import StringIO
stream = StringIO()
write_to_steam = redirect_stdout(stream)
with write_to_steam:
print("第一次调用")
print(stream.getvalue())
print('===================')
with write_to_steam:
print("第二次调用")
print(stream.getvalue())
result:
第一次调用
===================
第一次调用
第二次调用
这里我们创建了一个上下文管理器,他们都向StringIO中写入数据。由于redirect_stdout可重用,所以这段代码没有抛出异常。但是这种可以重用的上下文管理器不一定是线程安全的。如果线程中要使用,需要结合具体情景再做处理