AI智能
改变未来

Python_学习之上下文

目录

示例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 selfdef __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 = flagdef __enter__(self):print(\"int __enter__\")\"可以返回我们定义任何方法或实例化的对象\"return selfdef __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 selfdef __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)@staticmethoddef write_log():print(\"开始记录日志\")log = dict(req_body=\"request\", rsp_body=\"response\")f = open(\"my_log_test.txt\", \"w\", encoding=\"utf-8\")import jsonf.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 = flagself.data = datadef __enter__(self):return selfdef __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.flagdef write_action(self):\"\"\"开启多线程记录日志,发现异常不会抛出外层,但会将异常打印到控制台\"\"\"write_external_thread = threading.Thread(target=self.write_log, args=(self.data,))write_external_thread.setDaemon(True)write_external_thread.start()@staticmethoddef 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 = \"life 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类可以过滤指定的异常,不抛出
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Python_学习之上下文