Python通过装饰器统计递归函数调用次数与最大递归深度
问题根因
现有实现的核心缺陷:
- 计数器全局无差别累加,未识别递归链路的最外层调用入口,触发独立调用时不会重置历史统计值
- 缺少递归执行状态标记,无法区分“单次独立调用的起始点”和“递归链路内部的嵌套调用”,导致多次跨调用的统计值持续叠加
正确实现方案
核心逻辑是通过状态标记区分递归根调用与嵌套调用:在根调用触发时重置统计值,递归链执行过程中持续计数、跟踪最大深度,递归链完全退出后恢复状态标记,供下次根调用触发重置。
def depthcounter(func): def wrapper(*args, **kwargs): # 识别当前是否为递归链路的最外层根调用 is_root = not wrapper._active if is_root: # 根调用入口:重置本次链路的统计值 wrapper.ncalls = 0 wrapper.rdepth = 0 wrapper._current_depth = 0 wrapper._active = True # 累加调用计数、更新实时递归深度 wrapper.ncalls += 1 wrapper._current_depth += 1 # 记录本次链路达到的最大递归深度 if wrapper._current_depth > wrapper.rdepth: wrapper.rdepth = wrapper._current_depth try: result = func(*args, **kwargs) finally: # 递归栈回溯时实时更新当前深度 wrapper._current_depth -= 1 # 根调用栈帧弹出时,恢复活跃标记 if is_root: wrapper._active = False return result # 初始化装饰器挂载的公开属性与内部状态 wrapper.ncalls = 0 wrapper.rdepth = 0 wrapper._active = False wrapper._current_depth = 0 return wrapper
验证效果
使用提供的阶乘测试代码,最终输出完全匹配预期:
0 0 4 4 10 10 10 10 20 20 2 2
方案特性
- 兼容任意递归场景:无论线性递归还是带分支的递归(如斐波那契计算),均可正确统计总调用次数与最大递归深度
- 异常安全:通过
finally块处理状态恢复,即使被装饰函数抛出异常,也不会卡在活跃状态,保证后续调用可正常重置统计值 - 无侵入性:装饰器不修改原函数的执行逻辑与参数传递规则,对业务代码完全透明
内容的提问来源于stack exchange,提问作者Daniil Khlebnikov
相关产品推荐
相关产品推荐

