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

Python方法执行return后未退出,引发无限递归问题咨询

递归函数返回后未退出引发无限递归的问题分析

问题描述

你在实现shortest_path函数时遇到了一个棘手的问题:当函数触发第一个return path语句后,并没有按预期退出整个方法,反而跳转到倒数第二行再次调用自身,最终引发无限递归。按逻辑return后函数应该直接终止执行,你想弄清楚这背后的原因。

代码示例

import sys

# 假设以下辅助函数已实现
def load_data(directory):
    pass

def person_id_for_name(name):
    pass

def neighbors_for_person(person_id):
    pass

def main():
    if len(sys.argv) > 2:
        sys.exit("Usage: python degrees.py [directory]")
    directory = sys.argv[1] if len(sys.argv) == 2 else "small"
    print("Loading data...")
    load_data(directory)
    print("Data loaded.")
    source = person_id_for_name(input("Name: "))
    if source is None:
        sys.exit("Person not found.")
    target = person_id_for_name(input("Name: "))
    if target is None:
        sys.exit("Person not found.")
    path = shortest_path(source, source, target, set(), list())
    if path is None:
        print("Not connected.")
    else:
        degrees = len(path)
        print(f"{degrees} degrees of separation.")
        path = [(None, source)] + path
        print(path)

def shortest_path(original, source, target, visitedpeople=set(), path=list()):
    """
    Returns the shortest list of person_id that connect the source to the target.
    If no possible path, returns None.
    """
    if source == target:
        return []
    while source != target:
        destinations = neighbors_for_person(source)
        visitedpeople.add(source)
        neighbors = list()
        for x in range(len(destinations)):
            neighbors.append(destinations[x])
        if neighbors.__contains__(target):
            for neighbor in destinations:
                if neighbor == target:
                    path.append(neighbor)
                    return path
        else:
            if all(x in visitedpeople for x in neighbors):
                shortest_path(original, original, target, visitedpeople, path)
            else:
                for neighbor in destinations:
                    if neighbor not in visitedpeople:
                        path.append(neighbor)
                        visitedpeople.add(neighbor)
                        shortest_path(original, neighbor, target, visitedpeople, path)
    return []

问题根源分析

1. 递归调用未处理返回值,上层执行未终止

当你在代码中调用shortest_path(...)时,只是执行了递归,但没有处理递归的返回结果,也没有终止当前函数的执行流程。举个例子:

shortest_path(original, neighbor, target, visitedpeople, path)

这行代码执行完后,即使递归分支已经return path找到了目标路径,当前函数的代码还会继续往下走——比如回到for neighbor in destinations循环处理下一个邻居,或者回到外层的while循环再次执行循环体。这就导致即使递归找到了结果,上层函数仍会触发新的递归调用,最终引发无限递归。

2. 冗余的while循环加剧问题

你的函数已经用递归处理路径搜索,外层的while source != target循环完全是多余的。递归本身会逐层深入搜索,而这个while会让当前函数在递归返回后再次执行循环体,进一步加重了无限递归的情况。

3. 可变默认参数的潜在陷阱(虽当前调用未触发,但需注意)

Python的默认参数是在函数定义时初始化的,而不是每次调用时。也就是说,如果调用shortest_path时不传visitedpeople和path,所有调用会共享同一个set()和list()实例。虽然你在main里手动传了新的集合和列表,暂时避开了这个问题,但后续如果有其他调用方式,很容易出现状态混乱的问题。

修复方案

针对这些问题,我们可以逐步调整代码:

方案1:正确处理递归返回值,及时终止上层执行

在递归调用后检查返回结果,如果找到路径就立刻返回,终止当前函数的执行:

result = shortest_path(original, neighbor, target, visitedpeople, path)
if result is not None:
    return result

方案2:移除冗余的while循环

递归已经能处理路径的逐层搜索,外层while循环完全没必要,直接删除即可。

方案3:避免可变默认参数陷阱

把默认参数设为None,在函数内部初始化新的集合和列表,确保每次调用都有独立的状态:

def shortest_path(original, source, target, visitedpeople=None, path=None):
    if visitedpeople is None:
        visitedpeople = set()
    if path is None:
        path = []
    # 后续逻辑不变

修复后的核心代码示例

def shortest_path(original, source, target, visitedpeople=None, path=None):
    """
    Returns the shortest list of person_id that connect the source to the target.
    If no possible path, returns None.
    """
    if visitedpeople is None:
        visitedpeople = set()
    if path is None:
        path = []
    
    if source == target:
        return []
    
    # 标记当前节点已访问
    if source in visitedpeople:
        return None
    visitedpeople.add(source)
    
    destinations = neighbors_for_person(source)
    
    # 目标在邻居中,直接返回路径
    if target in destinations:
        return path + [target]
    
    # 递归搜索每个邻居
    for neighbor in destinations:
        if neighbor not in visitedpeople:
            result = shortest_path(original, neighbor, target, visitedpeople, path + [neighbor])
            if result is not None:
                return result
    
    # 所有邻居搜索完毕未找到路径
    return None

调整后,一旦某个递归分支找到目标路径,就会逐层返回结果,终止上层函数的执行,不会再触发多余的调用,彻底解决无限递归的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 15:42:46