如何使用Decorator装饰器打印递归函数调用并生成递归树
递归调用树打印装饰器实现
原代码缺陷说明
你之前写的装饰器存在三个核心问题,无法实现预期效果:
- 包装函数未透传原递归函数的返回值,递归链路执行到第一层后就会中断,无法触发完整的深层递归
- 没有递归深度追踪逻辑,无法将同一递归层级的调用归集到同一行输出
- 未区分顶层入口调用和递归内层调用,无法在全量递归执行完成后统一输出结构化的调用树
可直接使用的实现代码
完全不需要修改原有fib函数的内部逻辑,直接替换装饰器即可:
def print_call_tree(function): def wrapper(n): # 最外层入口调用时初始化递归状态 if not hasattr(wrapper, 'is_running'): wrapper.is_running = True wrapper.current_depth = 0 wrapper.level_records = [] try: result = wrapper(n) # 全量递归执行完成后按层级打印 print(f"for n = {n}:") for calls in wrapper.level_records: print(" " + ", ".join(calls)) return result finally: # 清理状态,避免多次调用装饰器函数时数据互相污染 del wrapper.is_running del wrapper.current_depth del wrapper.level_records # 所有递归调用的通用记录逻辑 call_repr = f"{function.__name__}({n})" # 初始化当前深度的记录列表 if len(wrapper.level_records) <= wrapper.current_depth: wrapper.level_records.append([]) wrapper.level_records[wrapper.current_depth].append(call_repr) # 进入下一层递归,深度+1 wrapper.current_depth += 1 res = function(n) # 退出当前层回到上一层,深度-1 wrapper.current_depth -= 1 return res return wrapper # 原有fib函数无需任何修改 @print_call_tree def fib(n): if n < 3: return 1 return fib(n-1) + fib(n-2) # 测试调用 fib(5)
输出效果
执行fib(5)时的输出和预期结构完全一致:
for n = 5: fib(5) fib(4), fib(3) fib(3), fib(2), fib(2), fib(1) fib(2), fib(1), fib(1), fib(0)
注:你示例中出现的
fib(-1)是因为示例用的fib终止条件和你给出的代码不一致,如果你把fib的终止条件改为if n < 2: return 1,就会自动打印出更深层的调用节点,装饰器不需要做任何调整。
内容的提问来源于stack exchange,提问作者Eran Daniel
相关产品推荐
相关产品推荐

