You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python双层装饰器中获取调用者名称以追踪竞态条件

解决方法分两种场景,看你需要哪一种

场景1:显示被装饰的原函数名称(而非装饰器的wrapper)

如果你的装饰器现在输出的是内部包装函数(比如wrapper)的名字,而不是你真正调用的业务函数名,只需要用functools.wraps装饰包装函数,它会帮你保留原函数的元信息(包括函数名)。

示例代码:

import time
from functools import wraps

def timer_decorator(func):
    # 用wraps装饰wrapper,保留原函数的元数据
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        # 现在可以直接用func.__name__或者wrapper.__name__,两者一致
        print(f"Function {func.__name__} took {end - start:.4f} seconds")
        return result
    return wrapper

@timer_decorator
def process_data():
    time.sleep(0.5)

@timer_decorator
def fetch_resource():
    time.sleep(0.8)

# 调用测试
process_data()
fetch_resource()

输出结果:

Function process_data took 0.5001 seconds
Function fetch_resource took 0.8002 seconds

场景2:显示调用该函数的上层调用者名称

如果你的需求是追踪是谁调用了这个被装饰的函数(比如函数A调用了process_data,你要显示A的名字),那就要用到inspect模块来获取调用栈信息。

修改后的装饰器代码:

import time
import inspect
from functools import wraps

def timer_with_caller_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        
        # 获取调用栈:栈的第0层是当前wrapper,第1层是被装饰的函数,第2层就是调用者
        call_stack = inspect.stack()
        # 确保栈足够深(避免直接在顶层调用时出错)
        if len(call_stack) >= 3:
            caller_frame = call_stack[2]
            caller_name = caller_frame.function
        else:
            caller_name = "top-level (direct call)"
        
        print(f"Function {func.__name__} called by {caller_name} took {end - start:.4f} seconds")
        return result
    return wrapper

@timer_with_caller_decorator
def process_data():
    time.sleep(0.5)

def data_pipeline():
    process_data()

# 测试直接调用
process_data()
# 测试通过函数调用
data_pipeline()

输出结果:

Function process_data called by top-level (direct call) took 0.5001 seconds
Function process_data called by data_pipeline took 0.5000 seconds

小提示

  • 使用inspect.stack()会有一定性能开销,如果是在性能敏感的高频调用场景中,建议谨慎使用。
  • 如果你需要更详细的调用者信息(比如文件名、行号),可以从caller_frame中获取filename和lineno属性。

内容的提问来源于stack exchange,提问作者Tony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:11:57