Python3循环中向列表追加元素异常问题求助
问题描述
我在Python3中迭代向列表添加元素时遇到困难,以下是最小可复现示例(MWE):
# Given a nested list of values, or sets sets = [[1, 2, 3], [1, 2, 4], [1, 2, 5]] # add a value to each sublist giving the number of that set in the list. n_sets = len(sets) for s in range(n_sets): (sets[s]).insert(0, s) # Now repeat those sets reps times reps = 4 expanded_sets = [item for item in sets for i in range(reps)] # then assign a repetition number to each occurance of a set. rep_list = list(range(reps)) * n_sets for i in range(n_sets * reps): (expanded_sets[i]).insert(0, rep_list[i]) expanded_sets
执行后得到的实际输出不符合预期:
[[3, 2, 1, 0, 0, 1, 2, 3], [3, 2, 1, 0, 0, 1, 2, 3], [3, 2, 1, 0, 0, 1, 2, 3], [3, 2, 1, 0, 0, 1, 2, 3], [3, 2, 1, 0, 1, 1, 2, 4], [3, 2, 1, 0, 1, 1, 2, 4], [3, 2, 1, 0, 1, 1, 2, 4], [3, 2, 1, 0, 1, 1, 2, 4], [3, 2, 1, 0, 2, 1, 2, 5], [3, 2, 1, 0, 2, 1, 2, 5], [3, 2, 1, 0, 2, 1, 2, 5], [3, 2, 1, 0, 2, 1, 2, 5]]
期望输出为:
[[0, 0, 1, 2, 3], [1, 0, 1, 2, 3], [2, 0, 1, 2, 3], [3, 0, 1, 2, 3], [0, 1, 1, 2, 4], [1, 1, 1, 2, 4], [2, 1, 1, 2, 4], [3, 1, 1, 2, 4], [0, 2, 1, 2, 5], [1, 2, 1, 2, 5], [2, 2, 1, 2, 5], [3, 2, 1, 2, 5]]
第一个循环后sets得到预期值,但第二个循环后原列表sets被意外修改,怀疑和列表的引用与拷贝有关,尝试过添加.copy()和切片操作,修改rep_list生成方式也未解决问题,使用Python 3.10.6版本,寻求解决办法。
问题原因
核心问题是列表的引用传递:
- 生成
expanded_sets时,列表推导式[item for item in sets for i in range(reps)]中的item是原sets中子列表的直接引用,而非独立拷贝。 - 因此
expanded_sets中同一组的4个元素都指向同一个原列表对象,每次对expanded_sets[i]执行insert操作,都会修改同一个底层列表,导致多次插入的内容叠加。 - 同时,修改
expanded_sets中的元素也会同步修改原sets中的子列表,因为它们指向同一个对象。
解决方法
在生成expanded_sets时,对每个子列表做浅拷贝,确保每个元素都是独立的新列表。可以用item.copy()或者切片item[:]实现:
修正后的代码:
sets = [[1, 2, 3], [1, 2, 4], [1, 2, 5]] n_sets = len(sets) for s in range(n_sets): sets[s].insert(0, s) reps = 4 # 这里添加.copy()生成独立拷贝 expanded_sets = [item.copy() for item in sets for i in range(reps)] rep_list = list(range(reps)) * n_sets for i in range(n_sets * reps): expanded_sets[i].insert(0, rep_list[i]) print(expanded_sets)
执行后即可得到期望输出:
[[0, 0, 1, 2, 3], [1, 0, 1, 2, 3], [2, 0, 1, 2, 3], [3, 0, 1, 2, 3], [0, 1, 1, 2, 4], [1, 1, 1, 2, 4], [2, 1, 1, 2, 4], [3, 1, 1, 2, 4], [0, 2, 1, 2, 5], [1, 2, 1, 2, 5], [2, 2, 1, 2, 5], [3, 2, 1, 2, 5]]
补充说明
如果子列表中还包含嵌套的可变对象(比如更深层的列表),则需要使用copy.deepcopy()进行深拷贝,但本案例中仅需浅拷贝即可解决问题。
内容的提问来源于stack exchange,提问作者zazizoma
相关产品推荐
相关产品推荐

