如何为带记忆化的递归函数实现单次计时的装饰器?
解决递归函数计时装饰器重复输出的问题
你的问题根源在于:装饰器直接替换了fib_mem函数,递归调用fib_mem时,实际调用的是被装饰后的inner函数,导致每一次递归都会执行计时逻辑,从而多次输出时间。而fib_rec没问题是因为它的递归是调用内部嵌套的fibo函数,而非被装饰的fib_rec本身。
下面是修改后的装饰器,仅对最外层函数调用执行一次计时:
from time import timer from typing import Callable from functools import wraps def time_dec(func: Callable): @wraps(func) def inner(*args, **kwargs): # 用函数属性标记是否正在执行最外层计时 if not getattr(inner, '_in_timing', False): inner._in_timing = True t1 = timer() try: # 执行原函数,保留返回值 result = func(*args, **kwargs) finally: # 无论函数是否抛出异常,都打印耗时并重置状态 print(f"函数执行耗时:{timer() - t1:.6f}秒") inner._in_timing = False return result else: # 递归调用时直接执行原函数,跳过计时逻辑 return func(*args, **kwargs) return inner
为什么这个方案有效:
- 通过给
inner函数添加_in_timing属性,追踪当前是否处于最外层计时状态 - 第一次调用时,设置
_in_timing为True,执行完整的计时流程;递归调用时,因_in_timing已为True,直接调用原函数,不触发计时打印 - 使用
try...finally确保即使函数执行出错,也能重置计时状态,避免后续调用异常 @wraps(func)保留原函数的元信息(如函数名、文档字符串),避免装饰器破坏原函数的特性
测试修改后的装饰器
用修改后的装饰器装饰fib_mem:
cache = {0: 0, 1: 1} @time_dec def fib_mem(n): if n in cache: return cache[n] cache[n] = fib_mem(n - 1) + fib_mem(n - 2) return cache[n]
调用fib_mem(20)只会输出一次完整的执行耗时,符合你的需求。
内容的提问来源于stack exchange,提问作者Roggab32
相关产品推荐
相关产品推荐

