为何按值传递仍在递归函数中修改原对象?求代码重构方案
解决递归分支中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
相关产品推荐
相关产品推荐

