本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。
个人其他博客地址:
简书:https://www.jianshu.com/u/d6960089b087
掘金:https://juejin.cn/user/2963939079225608
小钟同学 | 文 【原创】| QQ:308711822
如何有效进行资源管理闭合,自定义上下文管理器对象来帮忙!
但是在python中类有with语句经常见:如之前我们的flask库自定义的数据库的连接和关闭的时候就用到(这里使用的是装饰器的模式实现):
如下代码:
from contextlib import contextmanager
@contextmanager
def session_scope():
session = GetSession()
if session.is_closed():
# session.connection_context()
session.connect()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
然后我们使用的时候是直接可以使用:
with session_scope():
print([v for v in TestClassId.select().dicts()])
# 根据主键ID查询
print(TestClassId.get_by_id(1).test_class)
# 根据主键ID查询
print(TestClassId.get_or_none(TestClassId.test_class == 'b').test_class)
with是从Python一个语法糖,它是一种上下文管理协议,目的在于把我们之前常见一个开发 try,except 和finally 关键字和一些文件开关闭合资源分配释放等问题都简化。
总结起来使用python 提供的with主要的作用是:
常见的几个应用场景有:
如之前我们的一个打开文件和关闭文件的操作:
# 完成一个文件的额读取操作
f1 = open('tx1.txt', 'r',encoding='utf-8')
data = f1.read()
print(data)
# 关闭文件
f1.close()
with open('tx1.txt', 'r') as f1:
print(f1.read())
使用with即时再读取文件的过程中出现了异常,也能正常的关闭我们的f1.close()
本质上其实with是上下文管理:
类需要实现:
__ exit__()方法的3个参数,分别代表异常的类型、值、以及堆栈信息。
class ConmenManage(object):
def __init__(self,name):
self.name=name
def __enter__(self):
print("进入enter")
return self
def say(self):
print(self.name)
def __exit__(self,exc_type,exc_value,traceback):
print("退出exit")
print(exc_type,exc_value)
if __name__ == '__main__':
with ConmenManage('小钟同学') as xiaozhong:
xiaozhong.say()
输出的结果:
进入enter
小钟同学
退出exit
None None
异常的情况下:
class ConmenManage(object):
def __init__(self,name):
self.name=name
def __enter__(self):
print("进入enter")
return self
def say(self):
3534/0
print(self.name)
def __exit__(self,exc_type,exc_value,traceback):
print("退出exit")
print(exc_type,exc_value)
if __name__ == '__main__':
with ConmenManage('小钟同学') as xiaozhong:
xiaozhong.say()
输出:
进入enter
退出exit
Traceback (most recent call last):
<class 'ZeroDivisionError'> division by zero
File "D:/code/python/local_python/AntFlask/ceshi3.py", line 22, in <module>
xiaozhong.say()
File "D:/code/python/local_python/AntFlask/ceshi3.py", line 13, in say
3534/0
ZeroDivisionError: division by zero
在异常的情况也下也能做的进入到我们的__exit__执行我们的相关的异常的处理。
PS:exit() 方法中对变量exc_trackback进行检测,如果不为 None,表示发生了异常,返回 False 表示需要由外部代码逻辑对异常进行处理;
with语句的执行过程总结:
上面的xiaozhong是一种with语句的变量定义的方式,xiaozhong它是一个临时变量:甚至支持多变量如:
class ConmenManage(object):
def __init__(self,name):
self.name=name
def __enter__(self):
print("进入enter")
return self
def say(self):
print(self.name)
def __exit__(self,exc_type,exc_value,traceback):
print("退出exit")
print(exc_type,exc_value)
if __name__ == '__main__':
with ConmenManage('小钟同学') as xiaozhong,ConmenManage('小小同学') as xiaoxiao:
xiaozhong.say()
xiaoxiao.say()
输出的结果为:
进入enter
进入enter
小钟同学
小小同学
退出exit
None None
退出exit
所以多变量的情况,其实就是一种内嵌with的实现:
with ConmenManage('小钟同学') as xiaozhong,ConmenManage('小小同学') as xiaoxiao:
xiaozhong.say()
xiaoxiao.say()
和
with ConmenManage('小钟同学') as xiaozhong:
with ConmenManage('小小同学') as xiaoxiao:
xiaozhong.say()
xiaoxiao.say()
一个关于数据库简单的使用类的方式封装的示例:
class PgHelper(object):
"""操作postgresql数据库的类"""
def __init__(self, db):
self.connect = None
self.cursor = None
# 初始化数据库参数
self.db_name = db.get('db_name', '')
self.db_user = db.get('db_user', '')
self.db_pass = db.get('db_pass', '')
self.db_host = db.get('db_host', '')
self.db_port = db.get('db_port', '')
def __enter__(self):
"""初始化数据库链接"""
self.open_conn()
return self
def __exit__(self, type, value, trace):
"""关闭postgresql数据库链接"""
self.close_conn()
def open_conn(self):
"""连接数据库,并建立游标"""
try:
if not self.connect:
self.connect = psycopg2.connect(database=self.db_name, user=self.db_user, password=self.db_pass,
host=self.db_host, port=self.db_port)
return self.connect
except Exception as e:
logger.error('连接数据库失败:' + str(e.args))
# print('连接数据库失败:' + str(e.args))
return False
def close_conn(self):
"""关闭postgresql数据库链接"""
# 关闭游标
try:
if self.cursor:
self.cursor.close()
except Exception:
pass
# 关闭数据库链接
try:
if self.connect:
self.connect.close()
except Exception:
pass
def rollback(self):
"""回滚操作"""
try:
# 操作异常时,操作回滚
if self.connect:
self.connect.rollback()
self.close_conn()
except Exception as e:
logger.error('回滚操作失败:' + str(e.args))
def commit(self):
"""提交事务"""
try:
if self.connect:
self.connect.commit()
self.close_conn()
except Exception as e:
logger.error('提交事务失败:' + str(e.args))
代码示例:
from contextlib import contextmanager
@contextmanager
def session_scope():
session = GetSession()
if session.is_closed():
# session.connection_context()
session.connect()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
我们上面通过装饰器的形式进行数据库的链接,并且再装饰器的内部返回一个生成器对象。(关于生成器下次再说明一下),在执行内部过程如果出现了异常,则进行事务的回滚,不管最终处理怎么样,我们的会进行相关的链接的关闭。
https://www.jianshu.com/p/5b01fb36fd4c
以上是个人对Python的with语句用法一些简要阐述。
纯属个人实践中相关经验阐述总结,如有纰漏,还希望大佬们多多提点!小钟同学 | 文 【原创】| QQ:308711822
原文作者:程序员小钟同学;如有侵权,请联系管理员删除。