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

为何按值传递仍在递归函数中修改原对象?求代码重构方案

解决递归分支中Board意外被修改的问题

我明白你现在遇到的这个递归分支里board被意外修改的问题有多头疼——明明已经做了拷贝,结果同层级的分支还是拿到了被改坏的board,这确实让人困惑。咱们先拆解问题出在哪,再一步步重构代码解决它。

问题根源:浅拷贝的坑

你当前用的board[:]是浅拷贝,如果你的originalBoard是二维列表(比如每行是一个子列表),这个切片操作只会复制外层的列表容器,里面的每一行子列表还是和原对象共享引用的。哪怕你在paintPointsBlack里又做了一次board = originalBoard[:],修改board里的某个单元格时,还是会影响到原列表里的对应子列表,这就导致同层级的其他分支拿到的board已经被之前的分支修改了。

举个简单例子:

original = [[0,0],[0,0]]
copy_shallow = original[:]
copy_shallow[0][0] = 1
print(original)  # 输出 [[1,0],[0,0]],原列表被修改了!

重构方案:用深拷贝彻底切断引用

要解决这个问题,我们需要用深拷贝来创建完全独立的board副本,Python的copy模块里的deepcopy方法可以递归复制所有嵌套的对象,彻底切断和原对象的引用关系。

步骤1:导入copy模块

在代码开头引入深拷贝工具:

import copy

步骤2:修改paintPointsBlack的拷贝逻辑

把原来的浅拷贝替换成深拷贝,确保每次生成的board都是完全独立的:

def paintPointsBlack(originalBoard, point0, point1, point2):
    # 用deepcopy创建完全独立的副本,彻底切断与原对象的引用
    board = copy.deepcopy(originalBoard)
    # 这里执行你的涂黑逻辑,比如修改对应坐标的颜色
    # 示例:board[point0['row']][point0['col']] = 'black'
    return board

步骤3:修复fillTheBoard中的潜在修改点

还要注意movePointToWhitePoint函数——如果它会修改传入的board,那你在调用它之前必须先拷贝board,避免污染原对象:

def fillTheBoard(board, point):
    # 先创建board的深拷贝,避免movePointToWhitePoint修改原board
    board_copy = copy.deepcopy(board)
    movePointToWhitePoint(board_copy, point)
    
    if point['row'] == height - 1:
        print('last line. terminate')
        return
    elif point['row'] != height - 1:
        LCanFit = canPutLShape(board_copy, point)
        if LCanFit['total'] != 0:
            point0 = dict(point)
            if LCanFit['RdD'] == 1:
                # 这里补充point1和point2的定义逻辑
                point1 = {"row": point['row'] + 1, "col": point['col']}
                point2 = {"row": point['row'], "col": point['col'] + 1}
                newBoard = paintPointsBlack(board_copy, point0, point1, point2)
                fillTheBoard(newBoard, point0)
            # 其他LCanFit分支同理,保持相同的拷贝逻辑
            if LCanFit['DL'] == 1:
                # ... 你的point1、point2定义
                newBoard = paintPointsBlack(board_copy, point0, point1, point2)
                fillTheBoard(newBoard, point0)
            if LCanFit['RD'] == 1:
                # ... 你的point1、point2定义
                newBoard = paintPointsBlack(board_copy, point0, point1, point2)
                fillTheBoard(newBoard, point0)
            if LCanFit['DR'] == 1:
                # ... 你的point1、point2定义
                newBoard = paintPointsBlack(board_copy, point0, point1, point2)
                fillTheBoard(newBoard, point0)
        print("inspected everything around : ", point['row'], point['col'])
    else:
        return

额外注意事项

  • 检查所有操作board的辅助函数(比如canPutLShape),确保它们不会修改传入的board——如果有修改逻辑,也要在函数内部先做深拷贝。
  • 如果你的board是其他嵌套结构(比如包含自定义对象),deepcopy依然能处理,它会递归复制所有层级的对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:20:44