目录
示例1:查看上下文执行的顺序
示例2:动态控制上下文是否抛出异常
示例3:以装饰器的方式为功能函数加装上下文
示例4:过滤异常,不抛出
在之前我们进行过文件操作的学习时,我们为了不忘掉文件操作完毕后关闭文件file.close(),官方推荐推荐我们使用with……as 语句,这其实本质就是运用了python的上下文管理。
而所谓的上下文,其实就是服务运行的状态从进入到退出的一种过程,python中我们常常通过上下文来进行资源的创建与释放。
语法:with……as
本质:
程序执行with中的代码时,会自动先执行enter方法,返回在这个上下文中使用的对象句柄,程序执行完逻辑后自动调用exit来进行资源的释放
示例1:查看上下文执行的顺序
如果上下文中出现异常即执行逻辑代码过程中,上下文是可以捕获异常的,并且默认是抛出异常的
class MyContext: def __init__(self): print("in __init__") def __enter__(self): print("int __enter__") return self def __exit__(self, exc_type, exc_val, exc_tb): """""" print("in __exit__") print("异常的类型exc_type=", exc_type) print("异常抛出的值exc_type=", exc_val) print("异常的traceback对象exc_type=", exc_tb)if __name__ == '__main__': with MyContext() as t: print("执行代码逻辑……") raise Exception("错误解释")# 执行结果为"""in __init__int __enter__执行代码逻辑……in __exit__异常的类型exc_type= <class 'Exception'>异常抛出的值exc_type= 错误解释异常的traceback对象exc_type= <traceback object at 0x000001B52B5465C8>Traceback (most recent call last):File "D:/my_all_project/Frame_learning/test.py", line 27, in <module> raise Exception("错误解释")Exception: 错误解释"""
示例2:动态控制上下文是否抛出异常
如果功能函数逻辑中出现异常,而exit方法返回值等价于False就会抛出异常,否则不抛出异常,继续执行上下文外面的业务逻辑
class MyContext: def __init__(self, flag): print("in __init__") self.flag = flag def __enter__(self): print("int __enter__") "可以返回我们定义任何方法或实例化的对象" return self def __exit__(self, exc_type, exc_val, exc_tb): """""" print("in __exit__") print("异常的类型exc_type=", exc_type) print("异常抛出的值exc_type=", exc_val) print("异常的traceback对象exc_type=", exc_tb) return self.flagif __name__ == '__main__': with MyContext(True) as t: print("执行代码逻辑……") raise Exception("错误解释") print("===>当上下文不抛出异常时,此处可以被打印")# t 实际就是类Mycontext的实例化对象,其可以调用类中的任意实例方法和属性
示例3:以装饰器的方式为功能函数加装上下文
import contextlibclass MyContext(contextlib.ContextDecorator): def __init__(self): print(f'__init__()') def __enter__(self): print(f'__enter__()') return self def __exit__(self, exc_type, exc_val, exc_tb): print(f'__exit__()') print(f"exc_type:{exc_type}") try: self.write_log() except Exception as e: print(e) @staticmethod def write_log(): print("开始记录日志") log = dict(req_body="request", rsp_body="response") f = open("my_log_test.txt", "w", encoding="utf-8") import json f.write(json.dumps(log, ensure_ascii=False)) f.flush() f.close() raise Exception("本日志记录报错,不在影响功能函数的正常返回")@MyContext()def func(flag): code, desc = 1, "fail" try: if flag: raise Exception("测试上下文是否能捕获异常") else: code, desc = 0, "success" except Exception as e: print(f"本初捕获异常:{e},则不会再抛给上下文管理器中") else: code, desc = 0, "success" finally: return {"code": code, "desc": desc}if __name__ == '__main__': ret = func(True) print(ret)# 本小例是通过上下文初试为功能函数添加记录日志的功能,不因记录日志出现异常导致功能函数异常,也可以加一个开关,是否记录日志# 写日志的另一个版本import threadingclass WriteLogContext: def __init__(self, flag, data): """ :param flag: 异常日志是否抛出开关标识 :param data: 日志内容 """ self.flag = flag self.data = data def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): print("异常的类型exc_type=", exc_type) print("异常抛出的值exc_type=", exc_val) print("异常的traceback对象exc_type=", exc_tb) return self.flag def write_action(self): """开启多线程记录日志,发现异常不会抛出外层,但会将异常打印到控制台""" write_external_thread = threading.Thread(target=self.write_log, args=(self.data,)) write_external_thread.setDaemon(True) write_external_thread.start() @staticmethod def write_log(log): with open("test.txt", "a") as file: file.write("入库的操作模拟\n") file.write(f"{log}\n") file.flush() # 模拟异常 raise TypeError("模拟写日志过程中的异常,发现本处报错,并不会影响主功能函数响应")def access(): # 执行业务 print("business is begin") # 记录流水 log = "l����,����ife is short ,i use python ,i use it for make money" with WriteLogContext(flag=True, data=log) as f: f.write_action() # 响应 result = "business is success" return result
示例4:过滤异常,不抛出
import contextlibdef write_log(data): if data: print(111111) else: raise Exception("life")with contextlib.suppress(Exception): data = dict() write_log(data)# suppress类可以过滤指定的异常,不抛出