如何在运行多文件Python项目时自动打印所有执行的函数名?
无需手动加装饰器的函数调用追踪方案
方案1:使用sys.settrace全局追踪
Python内置的sys.settrace可以设置全局追踪函数,自动监控所有函数调用事件,完全不用修改原有项目代码。
示例代码
在项目入口文件的最顶部插入这段代码:
import sys import os # 定义项目根目录,用于过滤第三方库的函数 PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) def trace_calls(frame, event, arg): # 只处理函数调用事件 if event == 'call': func_name = frame.f_code.co_name func_file = frame.f_code.co_filename # 过滤掉内置/私有函数,以及第三方库的函数 if not func_name.startswith('_') and PROJECT_ROOT in func_file: rel_path = os.path.relpath(func_file, PROJECT_ROOT) print(f"执行函数: {func_name} | 文件: {rel_path}") # 返回自身以持续追踪后续调用 return trace_calls # 开启全局追踪 sys.settrace(trace_calls) # 导入并启动你的主程序 import your_main_module your_main_module.main()
注意点
- 这个方案会追踪所有层级的函数调用,包括嵌套调用和模块间的函数调用。
- 通过
PROJECT_ROOT过滤,可以只打印你自己项目里的函数,避免第三方库的输出干扰。 - 如果不需要过滤,直接去掉路径判断的逻辑即可。
方案2:动态包装指定模块的函数
如果只想追踪特定模块的函数,可以用inspect模块遍历模块成员,自动给所有函数加包装:
import inspect import your_target_module def trace_wrapper(func): def wrapped(*args, **kwargs): print(f"执行函数: {func.__name__}") return func(*args, **kwargs) return wrapped # 遍历模块中的所有函数,自动添加包装 for name, obj in inspect.getmembers(your_target_module, inspect.isfunction): setattr(your_target_module, name, trace_wrapper(obj)) # 运行模块主逻辑 your_target_module.main()
扩展
如果要处理多个模块,可以写个递归函数,遍历所有导入的模块进行包装,不过要注意避免重复包装。
方案3:自定义导入钩子批量处理
通过自定义导入钩子,可以在模块加载时自动为其中的函数添加追踪逻辑,适合整个项目的批量处理,无需逐个模块手动操作:
import sys import types from functools import wraps def trace_func(func): @wraps(func) def wrapper(*args, **kwargs): print(f"执行函数: {func.__name__}") return func(*args, **kwargs) return wrapper class TraceImportHook: def find_module(self, name, path=None): # 只处理你的项目模块,替换成实际的包名前缀 if name.startswith("your_project_package."): return self return None def load_module(self, name): if name in sys.modules: return sys.modules[name] # 导入原始模块 module = __import__(name) sys.modules[name] = module # 遍历模块内的所有函数并包装 for attr_name, attr in module.__dict__.items(): if isinstance(attr, types.FunctionType): setattr(module, attr_name, trace_func(attr)) return module # 注册导入钩子,放在所有模块导入前 sys.meta_path.insert(0, TraceImportHook()) # 启动主程序 import your_project_main your_project_main.main()
说明
- 这个钩子会拦截指定前缀的模块导入,自动给模块内的所有函数加上追踪逻辑。
- 把
your_project_package.替换成你项目的包名前缀,就能只处理自己的代码。
内容的提问来源于stack exchange,提问作者Niandra Lades
相关产品推荐
相关产品推荐

