Python动态创建三维列表时索引操作失效的问题及解决
Python三维计数器列表动态创建问题与解决
我在实现加权和模型(Weighted sum model)时,需要用一个三维计数器列表记录2个获胜者的获胜次数,结构是:2个获胜者维度 → 每个维度下3个决策问题项 → 每个问题项包含2个决策子项。
一开始我用这段代码动态声明计数器:
counter = [[[0,0]]*len(maniArrays)]*len(maniArrays[0])
接着写循环更新计数器:
# 遍历[[1, 9], [2, 9], [2, 6]]中的每个元素 for paar_idx, paar in enumerate(maniArrays): # 遍历[1, 9]中的每个元素 for einzel_idx, einzel in enumerate(paar): # komb[paar_idx]对应值为[1, 2, 2] if einzel == komb[paar_idx]: counter[max_idx][paar_idx][einzel_idx] += 1
但出现异常:本该只对counter[max_idx][paar_idx][einzel_idx]位置加1,结果所有对应位置同时递增。比如:
Combination [1, 2, 2] -> [[1, 2, 4], [5, 2, 2]] -> Winner: A 2 Counter (before) [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]] Counter (after) [[[3, 0], [3, 0], [3, 0]], [[3, 0], [3, 0], [3, 0]]]
换成手动静态声明counter = [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]后功能完全正常,说明问题出在动态列表的声明方式上。
问题根源
Python里用*创建多维列表时,并不会生成独立的子列表,而是创建同一列表对象的引用。比如[[[0,0]]*len(maniArrays)]*len(maniArrays[0])中,所有第二层的列表都指向同一个列表,所有第三层的[0,0]也是同一个引用。修改其中任何一个位置,其他引用该对象的位置都会跟着变。
正确的动态创建方法
方法1:嵌套列表推导式(推荐)
用列表推导式逐个生成独立的子列表,确保每个子结构都是全新的对象:
# 2代表获胜者数量,根据实际情况调整;len(maniArrays)是决策问题项数量,每个子项长度固定为2 counter = [[[0, 0] for _ in range(len(maniArrays))] for _ in range(2)]
如果每个决策问题项的子项长度不固定(由maniArrays中每个paar的长度决定),可以写成:
counter = [[[0]*len(paar) for paar in maniArrays] for _ in range(2)]
方法2:嵌套循环手动构建
如果不习惯列表推导式,也可以用循环一步步创建:
counter = [] # 遍历获胜者维度 for _ in range(2): decision_items = [] # 遍历决策问题项 for _ in range(len(maniArrays)): # 创建决策子项计数器 sub_item_counter = [0, 0] decision_items.append(sub_item_counter) counter.append(decision_items)
用以上任意一种方式创建计数器后,再执行更新逻辑,就只会修改指定位置的数值,不会出现批量变化的问题。
内容的提问来源于stack exchange,提问作者icecase
相关产品推荐
相关产品推荐

