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

Python生成器函数遍历中断后出现异常耦合行为的问题排查

问题根源:Python可变默认参数的隐形陷阱

兄弟,这个问题我之前踩过一模一样的坑!核心原因就是Python函数的可变默认参数只会在函数定义时初始化一次,而不是每次调用函数都重新创建新的对象。你看你的get_paths函数里,path=[]和visited=set([])这俩默认参数,其实所有对get_paths的调用,都在共享同一个列表和集合!

具体发生了啥?

  • 第一次调用get_paths时,生成器开始执行,visited集合跟着递归不断添加、移除节点,path也在逐步拼接路径。
  • 你第一个循环用break跳出,相当于生成器中途暂停了——此时visited的状态停在了中途(不是空集合),生成器的执行上下文也保留了这个状态。
  • 第二次再调用get_paths时,函数并没有新建空的path和visited,而是直接用上一次剩下的那个visited集合!这就导致第二次的生成器不是从头开始找路径,而是从第一次暂停的位置继续往下跑,自然只输出后续的路径,而不是全部。

为啥不break就正常?

如果第一次循环不break,生成器会把所有路径都跑完,最后递归里的visited.remove(s)会把所有加进去的节点都移除干净,visited回到空集合状态。第二次调用时状态是干净的,所以能正常输出所有路径。

为啥重跑函数定义单元格就好?

重跑函数定义单元格时,相当于重新定义了get_paths函数,这时候默认参数path=[]和visited=set([])会被重新初始化,变成新的空列表和集合,后续调用自然就从头开始了。

怎么修复?

要解决这个问题,得确保每次调用函数都创建新的可变对象,避开默认参数的坑。修改成这样就行:

def get_paths(ug, s, t, path=None, visited=None):
    # 每次调用时才初始化新的列表和集合
    if path is None:
        path = []
    if visited is None:
        visited = set()
    
    if s == t:
        yield path.copy()  # 返回副本,避免后续修改影响已生成的路径
    visited.add(s)
    for n in ug[s]:
        if n in visited:
            continue
        yield from get_paths(ug, n, t, path + [n], visited)
    visited.remove(s)

另外提一句,yield path的时候最好返回path.copy(),因为列表是可变对象,如果后续代码修改了生成的路径,会影响已经yield出来的结果,返回副本就安全多了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:17:23