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

如何在Python中获取函数调用名称与参数以分析依赖避免递归错误

函数依赖分析与递归问题解决方案

问题描述

我有一批仅接受单个参数x的函数,当函数数量较多时,计算过程中会出现RecursionError这类错误。我想提前理清函数之间的依赖关系,优先计算无依赖的函数并缓存结果,以此完成所有函数的计算。

示例代码:

def func_a(x):
    if x == 1:
        return func_b(x)
    return func_a(x-1) + func_c(x+1)


def func_b(x):
    return x


def func_c(x):
    return func_b(x)

需求目标

我希望传入类似(func_a, 5)的函数与参数元组,得到该函数会调用的所有函数及其对应参数,比如:

(func_a, 5) --> [(func_b, 4), (func_c, 6)]

其他示例:

(func_a, 1) --> [(func_b, 1)]
(func_c, 3) --> [(func_b, 3)]
(func_b, 1) --> []

已尝试方案

我用过@lru_cache装饰器,但解决不了RecursionError问题,执行print(func_a(500))会抛出:

RecursionError: maximum recursion depth exceeded

我还查过inspect模块,但没找到可行的解决办法。

解决方案

1. 静态分析函数依赖(基于AST)

通过Python的ast模块解析函数源代码,提取调用的其他函数及对应的参数值,无需执行函数即可分析依赖,从根源避免递归错误。

import ast
import inspect

def get_function_dependencies(func, x):
    # 获取函数源代码并解析成AST树
    source = inspect.getsource(func)
    tree = ast.parse(source)
    
    dependencies = []
    # 遍历AST节点寻找函数调用
    for node in ast.walk(tree):
        if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
            called_func_name = node.func.id
            # 确认被调用函数在当前全局作用域中
            if called_func_name in globals():
                called_func = globals()[called_func_name]
                # 计算传入的参数值
                try:
                    local_vars = {'x': x}
                    arg_value = eval(compile(ast.Expression(node.args[0]), '<ast>', 'eval'), globals(), local_vars)
                    dependencies.append((called_func, arg_value))
                except Exception:
                    # 复杂参数逻辑可根据实际情况扩展处理
                    pass
    # 去重后返回
    return list(set(dependencies))

测试效果:

print(get_function_dependencies(func_a, 5))  # 输出类似 [(<function func_c at 0x...>, 6), (<function func_b at 0x...>, 4)]
print(get_function_dependencies(func_a, 1))  # 输出 [(<function func_b at 0x...>, 1)]
print(get_function_dependencies(func_c, 3))  # 输出 [(<function func_b at 0x...>, 3)]
print(get_function_dependencies(func_b, 1))  # 输出 []

2. 动态追踪函数调用(拦截递归执行)

如果静态分析无法覆盖复杂的分支逻辑,可使用sys.settrace追踪函数调用,拦截递归执行过程,只记录依赖关系不实际完成递归。

import sys

def track_dependencies(target_func, x):
    dependencies = []
    processed = set()

    def trace_handler(frame, event, arg):
        if event == 'call':
            func_name = frame.f_code.co_name
            current_x = frame.f_locals.get('x')
            # 只处理目标相关的自定义函数
            if func_name in globals() and current_x is not None:
                current_func = globals()[func_name]
                key = (current_func, current_x)
                if key not in processed and key != (target_func, x):
                    dependencies.append(key)
                    processed.add(key)
                # 拦截当前函数执行,避免递归深入
                return lambda *args, **kwargs: None
        return trace_handler

    # 设置追踪器并尝试调用目标函数
    sys.settrace(trace_handler)
    try:
        target_func(x)
    except Exception:
        # 拦截后的返回会触发错误,直接忽略
        pass
    finally:
        sys.settrace(None)
    
    return list(set(dependencies))

3. 基于依赖的迭代计算与缓存

拿到依赖关系后,用拓扑排序的思路迭代计算:优先处理无依赖的函数,缓存结果,确保计算过程不会触发递归。

from collections import deque

def compute_with_dependencies(target_func, x):
    cache = {}
    task_queue = deque([(target_func, x)])
    
    while task_queue:
        func, arg = task_queue.popleft()
        if (func, arg) in cache:
            continue
        
        deps = get_function_dependencies(func, arg)
        # 检查所有依赖是否已缓存
        all_deps_ready = all(dep in cache for dep in deps)
        
        if all_deps_ready:
            # 安全计算并缓存结果
            cache[(func, arg)] = func(arg)
        else:
            # 依赖未完成,重新加入队列,先处理依赖
            task_queue.append((func, arg))
            # 添加未处理的依赖到队列头部,优先计算
            for dep in deps:
                if dep not in task_queue and dep not in cache:
                    task_queue.appendleft(dep)
    
    return cache[(target_func, x)]

测试func_a(500):

print(compute_with_dependencies(func_a, 500))  # 不会触发RecursionError,顺利得到结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:53:18