为何修改多维列表中一个元素会导致其他元素同步变更?
为何修改列表中的一个元素会导致其他值发生变化?
我在编写代码时遇到一个问题:修改棋盘列表中的单个元素后,其他位置的元素也同步发生了变化。相关代码及现象如下:
初始化棋盘的代码
def initial_state(): """ Returns starting state of the board. """ base = [[None, None, None], [None, None, None], [None, None, None]] goof = [[None, None, None], [None, None, None], [None, None, None]] for i in range(3): for j in range(3): goof[i][j] = base.copy() return goof
执行操作的代码
def result(board, action): """ Returns the board that results from making move (i, j) on the board. """ r_board = copy.deepcopy(board) r_action = action if r_board[r_action[0]][r_action[1]][r_action[2]][r_action[3]]!= None: raise ValueError else: turn = player(r_board) r_board[r_action[0]][r_action[1]][r_action[2]]= turn return r_board
现象
当我手动为board[0][0][0][0]赋值"X",或者通过result函数修改某个位置后,打印出的棋盘所有对应位置都变成了"X",示例输出如下:
[[[['X', None, None], [None, None, None], [None, None, None]], [['X', None, None], [None, None, None], [None, None, None]], [['X', None, None], [None, None, None], [None, None, None]]], [[['X', None, None], [None, None, None], [None, None, None]], [['X', None, None], [None, None, None], [None, None, None]], [['X', None, None], [None, None, None], [None, None, None]]], [[['X', None, None], [None, None, None], [None, None, None]], [['X', None, None], [None, None, None], [None, None, None]], [['X', None, None], [None, None, None], [None, None, None]]]]
请问为何会出现修改单个元素导致其他元素同步变更的情况?
问题根源
问题出在initial_state函数的初始化逻辑里:
base是一个二维列表(包含3个子列表),你使用base.copy()时,这是浅拷贝操作。浅拷贝只会复制外层列表的引用,而里面的子列表(比如[None, None, None])并不会被复制,所有goof[i][j]指向的base.copy()结果,其内部的子列表都共享同一个引用。- 也就是说,
goof[0][0]、goof[0][1]……goof[2][2]这些位置的二维列表,它们的内部子列表都是同一个对象。当你修改其中任意一个子列表里的元素时,所有共享该引用的位置都会同步变化。
修复方法
你有两种方式解决这个问题:
方法1:使用深拷贝初始化
导入copy模块,对base进行深拷贝,确保所有层级的列表都被复制:
import copy def initial_state(): base = [[None, None, None], [None, None, None], [None, None, None]] goof = [[None, None, None], [None, None, None], [None, None, None]] for i in range(3): for j in range(3): goof[i][j] = copy.deepcopy(base) return goof
方法2:每次生成新的二维列表
不依赖拷贝,直接在循环里生成全新的二维列表,避免引用共享:
def initial_state(): goof = [[None, None, None], [None, None, None], [None, None, None]] for i in range(3): for j in range(3): # 每次生成新的3x3列表 goof[i][j] = [[None, None, None], [None, None, None], [None, None, None]] return goof
这样修改后,每个goof[i][j]都是独立的二维列表,修改其中一个元素就不会影响其他位置了。
内容的提问来源于stack exchange,提问作者Nirav Krishnakumar
相关产品推荐
相关产品推荐

