如何写上下文管理器?
要自己实现这样一个上下文管理,要先知道上下文管理协议。
简单点说,就是在一个类里,实现了__enter__和__exit__的方法,这个类的实例就是一个上下文管理器。
在 写__exit__ 函数时,需要注意的事,它必须要有这三个参数:
exc_type:异常类型
exc_val:异常值
exc_tb:异常的错误栈信息
当主逻辑代码没有报异常时,这三个参数将都为None
为什么要使用上下文管理器?
这和 Python 崇尚的优雅风格有关。
可以以一种更加优雅的方式,操作(创建/获取/释放)资源,如文件操作、数据库连接;
可以以一种更加优雅的方式,处理异常;
第一种,我们上面已经以资源的连接为例讲过了。
第二种,会被大多数人所忽略。这里会重点讲一下。
大家都知道,处理异常,通常都是使用 try…execept… 来捕获处理的。这样做一个不好的地方是,在代码的主逻辑里,会有大量的异常处理代理,这会很大的影响我们的可读性。
好一点的做法呢,可以使用 with 将异常的处理隐藏起来。
基于python 的contextlib实现上下文管理
@contextlib.contextmanager装饰器使用
# -*- coding: UTF-8 -*-
import contextlib
import random
import threading
import time
import pymysql
@contextlib.contextmanager
def FileHander(filename):
handler = open(filename, 'r')
try:
yield handler
except Exception as err:
print(err)
finally:
handler.close()
return
with FileHander(r"E:\Blob\requirments.txt") as f:
for i in f.readlines():
print(i)
HOST = "xxx.xxx.x.x"
PORT = 3306
USER = "xxx"
PASSWORD = "xxx"
DATABASE = "xxx"
@contextlib.contextmanager
def DBConnect(**kwargs):
host = kwargs.get("host")
user = kwargs.get("user")
pwd = kwargs.get("pwd")
port = kwargs.get("port")
database = kwargs.get("database")
conn = pymysql.connect(host=host, port=port, user=user, password=pwd, database=database, charset="utf8")
cursor = conn.cursor()
try:
yield (conn,conn.cursor)
except Exception as err:
print(err)
finally:
cursor.close()
conn.close()
kw = dict(host=HOST, port=PORT, user=USER, pwd=PASSWORD, database=DATABASE)
def connectDB(i):
with DBConnect(**kw) as c:
conn, cursor = c[0], c[1]
print(f"id:{i};{id(conn)}")
print(f"id:{i};{id(cursor)}")
import threading
ts = [threading.Thread(target=connectDB,args=(i,)) for i in range(3)]
for i in ts:
i.start()
for i in ts:
i.join()