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

如何使用inspect模块递归获取Python函数及被调用函数的源代码

递归获取Python函数内部所有调用函数的源代码实现

实现思路

  • 依赖inspect模块获取目标函数的源码、关联的全局命名空间,判断对象是否为可获取源码的用户自定义函数
  • 依赖ast模块解析函数源码的抽象语法树,遍历提取所有函数调用节点的标识符
  • 维护已访问函数的全局集合,避免循环调用导致的无限递归,同时跳过无法获取源码的内置函数、C扩展函数
  • 对每个提取到的被调用函数,递归执行上述流程,最终汇总所有关联函数的源码

完整代码实现

import inspect
import ast
import types
from typing import Dict, Callable

def get_all_source_code_recursively(func: Callable, visited: set = None) -> Dict[str, str]:
    # 初始化已访问集合,避免循环递归
    if visited is None:
        visited = set()
    source_map = {}
    
    # 跳过非函数对象、已访问过的函数、内置/C扩展实现的函数
    if not isinstance(func, types.FunctionType) or func in visited or not inspect.getsourcefile(func):
        return source_map
    
    # 标记当前函数为已访问,获取当前函数源码
    visited.add(func)
    try:
        func_source = inspect.getsource(func)
        source_map[func.__name__] = func_source
    except OSError:
        return source_map
    
    # 解析函数源码为AST,提取所有调用节点
    try:
        tree = ast.parse(func_source)
    except SyntaxError:
        return source_map
    
    for node in ast.walk(tree):
        if isinstance(node, ast.Call):
            # 获取被调用函数的标识符
            if isinstance(node.func, ast.Name):
                func_name = node.func.id
            elif isinstance(node.func, ast.Attribute):
                # 处理方法调用的情况,这里只提取方法名,可根据需求调整
                func_name = node.func.attr
            else:
                continue
            
            # 从当前函数的全局命名空间查找函数对象
            if func_name in func.__globals__:
                called_obj = func.__globals__[func_name]
                # 递归获取被调用函数的源码
                sub_source = get_all_source_code_recursively(called_obj, visited)
                source_map.update(sub_source)
    
    return source_map

使用示例

# 测试用嵌套调用函数
def helper_func1():
    print("这是辅助函数1")

def helper_func2():
    helper_func1()
    return 100

def some_func(x: int):
    res = x + 2
    helper_func2()
    print(f"计算结果为{res}")

# 执行获取所有源码
all_source = get_all_source_code_recursively(some_func)
# 打印结果
for func_name, source in all_source.items():
    print(f"===== 函数 {func_name} 的源码 =====")
    print(source)

运行后会依次输出some_func、helper_func2、helper_func1三个函数的完整源码。

注意事项

  • 只能识别静态定义的函数调用,动态调用(如getattr(obj, "func_name")()、eval执行的函数调用)无法被AST解析,不会被纳入结果
  • 闭包内引用的非全局作用域函数无法从__globals__中获取,不会被纳入结果
  • 第三方库的C扩展实现函数、Python内置函数无法获取源码,会被自动跳过

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 14:27:01