如何在递归函数中使用Python装饰器?解决计时重复输出问题
解决递归函数计时装饰器重复输出问题,兼容迭代函数
原装饰器的问题在于递归调用时每一层都会触发计时逻辑,导致输出多个耗时值。我们需要修改装饰器,让它只在最外层调用时统计总耗时,同时保持对迭代函数的兼容性。
方案1:单线程场景简易实现
利用函数属性标记当前是否处于计时流程中,仅在最外层执行计时逻辑:
import datetime def timed(func): def wrapper(*args, **kwargs): # 判断是否为最外层调用 if not wrapper._is_timing: wrapper._is_timing = True start = datetime.now() result = func(*args, **kwargs) elapsed = datetime.now() - start print(f"总耗时: {elapsed.microseconds / 1000} ms") wrapper._is_timing = False return result # 内层递归调用,直接执行原函数 return func(*args, **kwargs) # 初始化计时标志 wrapper._is_timing = False return wrapper
原理说明
- 给
wrapper函数添加_is_timing属性,作为是否正在计时的标记 - 首次调用(最外层)时,
_is_timing为False,开启计时并执行原函数,结束后输出总耗时并重置标记 - 递归调用时,
_is_timing已被设为True,直接执行原函数,不触发计时输出
方案2:多线程安全实现
如果你的代码涉及多线程调用,使用线程局部存储避免不同线程的计时状态互相干扰:
import datetime import threading def timed(func): # 线程局部变量,每个线程独立维护计时状态 local_state = threading.local() def wrapper(*args, **kwargs): # 检查当前线程是否处于计时中 if not getattr(local_state, 'is_timing', False): local_state.is_timing = True start = datetime.now() result = func(*args, **kwargs) elapsed = datetime.now() - start print(f"总耗时: {elapsed.microseconds / 1000} ms") local_state.is_timing = False return result return func(*args, **kwargs) return wrapper
测试验证
归并排序(递归函数)
使用修改后的装饰器装饰merge函数:
def _merge_sorted(l, r): i = j = 0 temp = [] while i < len(l) and j < len(r): if l[i] <= r[j]: temp.append(l[i]) i += 1 else: temp.append(r[j]) j += 1 temp.extend(l[i:]) temp.extend(r[j:]) return temp @timed def merge(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left = merge(arr[:mid]) right = merge(arr[mid:]) return _merge_sorted(left, right) # 调用后仅输出一次总耗时 merge([5,4,3,2,1])
输出示例:
总耗时: 0.062 ms
冒泡排序(迭代函数)
装饰迭代函数也能正常工作:
@timed def bubble_sort(arr): n = len(arr) for i in range(n): swapped = False for j in range(0, n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] swapped = True if not swapped: break return arr bubble_sort([5,4,3,2,1])
输出示例:
总耗时: 0.038 ms
内容的提问来源于stack exchange,提问作者Hadi Zorkot
相关产品推荐
相关产品推荐

