如何在调用方try/except触发前拦截被调用模块内部函数的错误
Python模块级全局异常捕获实现方案
有两种成熟的实现方式可以满足需求,不需要在每个业务函数内单独编写try/except逻辑,所有异常处理逻辑都可以统一维护在mymodule内部。
方案1:通用装饰器+批量挂载
该方案兼容性最好,支持所有Python版本,对业务函数无侵入:
# mymodule.py 内部代码 import functools import types # 统一异常处理逻辑,所有内部错误都会先进入这里 def __handle_internal_error(e: Exception): # 这里编写统一的错误处理逻辑,比如日志记录、监控上报、兜底计算等 print(f"mymodule捕获内部错误:{str(e)}") # 需要抛给moduleA处理就保留raise,不需要抛的话注释raise,返回兜底值即可 raise e # 异常捕获装饰器 def __catch_error(func): @functools.wraps(func) def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: __handle_internal_error(e) return wrapper # ------------------- 以下是你的业务函数 ------------------- def func1(): # 你的业务逻辑,不需要加任何try/except 1/0 # 模拟报错 def func2(): # 你的业务逻辑 int("abc") # 模拟报错 # 剩余13个业务函数... # ------------------- 模块加载时自动给所有业务函数加装饰器 ------------------- for func_name, func_item in globals().items(): # 筛选当前模块的公开业务函数,排除私有函数、导入的外部函数 if isinstance(func_item, types.FunctionType) \ and not func_name.startswith("__") \ and func_item.__module__ == __name__: globals()[func_name] = __catch_error(func_item)
方案2:自定义模块类动态包装(Python 3.7+支持)
该方案侵入性更低,只有当外部实际调用函数时才会动态添加异常捕获逻辑:
# mymodule.py 内部代码 import sys import functools # 统一异常处理和装饰器逻辑和方案1完全一致,此处省略 def __handle_internal_error(e: Exception): print(f"mymodule捕获内部错误:{str(e)}") raise e def __catch_error(func): @functools.wraps(func) def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: __handle_internal_error(e) return wrapper # ------------------- 以下是你的业务函数,不需要做任何修改 ------------------- def func1(): 1/0 def func2(): int("abc") # 剩余13个业务函数... # ------------------- 替换默认模块类实现动态包装 ------------------- class __CustomModule(sys.modules[__name__].__class__): def __getattr__(self, item_name): item = super().__getattr__(item_name) # 只给公开可调用的业务函数加异常捕获 if callable(item) and not item_name.startswith("__"): return __catch_error(item) return item sys.modules[__name__].__class__ = __CustomModule
两种方案都可以保证所有mymodule内部的错误,会先经过你定义的统一处理逻辑,再决定是否要抛给上游的moduleA。
内容的提问来源于stack exchange,提问作者ThomasAJ
相关产品推荐
相关产品推荐

