起因
做一个项目时,遇到一个场景,类似于将多行文字录入在二级列表中,即父列表中存放多个子列表,,每个子列表代表一行,所以子列表内的每一项就是一个文字。注意:这只是举例,实际应用中不是存文字,仅仅说明一种类似的场景罢了。
出错
一开始觉得这个挺简单的,因为我是知道有多少行的,所以,我一开始就使用了
rows = [[]] * N
其中N表示行数,这样,我就可以迭代行数据,每一行里的,处理完一个字符,就类似
for i, row in enumerate(data):
for char in row:
processed = process(char) # 处理单个字符
rows[i].append(processed)
结果,实际执行的结果并不是我预想的一样,举例说明一下,假设有两行数据,process函数也是直接返回结果,那么data如果是
[
[1, 2],
[3, 4]
]
的情况,结果应该也是如此才对,结果实际结果如下:
[
[1, 2, 3, 4],
[1, 2, 3, 4]
]
解决
其实看到结果,差不多就知道原因了,问题出在[[]]*N上,根据语义,这里是将[]复制N次,但是这里的操作是复制了对象的引用,而不是值拷贝。
所以,比如[[]]*2得到的[[], []],两个[]元素其实引用的都是同一个,简单的测试即可验证。
a = [[]] * 3
a[0].append(1)
print(a)
这里的结果是[[1], [1], [1]],即对a[0]的操作,和对a[1],a[2]的操作完成一致的。
所以,假设知道是多少行了,其实用以下方法,就可以保证每个元素都是新建的,而不是引用的复制。
rows = [[] for i in range(N)]
这里用了列表表达式,里面每个[]都是单独创建的。