Python如何适配任意参数函数 用装饰器实现通用计时功能
原生实现任意参数函数执行耗时统计方案
你不需要手动判断参数个数写分支,Python原生的可变参数和解包语法可以直接适配任意合法参数组合的函数,完全不需要依赖第三方库。
核心原理
Python中*和**两个符号可以实现可变参数的打包与解包:
- 定义函数时写
*args会把传入的所有多余位置参数打包为元组 - 定义函数时写
**kwargs会把传入的所有多余关键字参数打包为字典 - 调用函数时写
*可迭代对象会把对象拆分为一个个独立的位置参数传入 - 调用函数时写
**字典会把字典拆分为一个个独立的关键字参数传入
靠这个特性就可以自动适配任意参数数量的函数,只要传入的参数和目标函数的定义匹配就能正常运行。
方案1:普通函数传参实现
直接把目标函数作为第一个参数传入,后面跟原函数需要的所有参数即可,不需要提前把参数整理成列表,也不需要判断参数个数:
import time def get_function_time(func, *args, **kwargs): # 短耗时场景推荐替换为time.perf_counter(),计时精度更高 start_time = time.time() # 解包参数执行原函数,同时保留原函数返回值 func_result = func(*args, **kwargs) cost = time.time() - start_time # 返回耗时和原函数执行结果,避免丢失原函数的返回值 return cost, func_result
使用示例
# 无参函数 def func1(): time.sleep(1) return "func1 finish" # 2个位置参数的函数 def func2(a, b): time.sleep(0.5) return a + b # 带默认参数、支持关键字传参的函数 def func3(a, b, c=3, d=None): time.sleep(0.2) return f"{a}-{b}-{c}-{d}" # 直接按原函数的参数传参即可,不需要额外包装 cost1, res1 = get_function_time(func1) cost2, res2 = get_function_time(func2, 10, 20) cost3, res3 = get_function_time(func3, 1, 2, d="test") print(cost1, res1) print(cost2, res2) print(cost3, res3)
如果你之前习惯把参数整理到列表里传递,也只需要在调用时直接解包列表即可,不需要写分支判断长度:
def get_function_time_list_params(func, param_list: list = None, param_dict: dict = None): param_list = param_list or [] param_dict = param_dict or {} start = time.time() res = func(*param_list, **param_dict) return time.time() - start, res
方案2:装饰器实现(更常用的无侵入方案)
如果需要批量给多个函数加耗时统计,用装饰器可以做到不修改原函数的调用逻辑,代码更简洁:
import time from functools import wraps def timer(func): # 加wraps装饰器可以保留原函数的元信息(比如函数名、注释文档) @wraps(func) def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) cost = time.time() - start print(f"[Timer] 函数 {func.__name__} 执行耗时: {cost:.4f}s") return res return wrapper
使用示例
直接给需要统计耗时的函数加上@timer装饰器即可,后续调用原函数的时候会自动打印耗时:
@timer def test_func(name, age, city="Beijing"): time.sleep(0.3) return f"User: {name}, {age} years old, live in {city}" # 正常调用原函数,不需要修改传参逻辑 result = test_func("Zhang San", 25, city="Shanghai") print(result)
补充说明
如果需要统计执行时间非常短的函数(比如毫秒、微秒级),建议把time.time()替换为time.perf_counter(),后者是Python专门为性能基准测试设计的计时接口,精度更高,不会受系统时间同步调整的影响。
内容的提问来源于stack exchange,提问作者offerrall
相关产品推荐
相关产品推荐

