持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
python 克隆
通常谨慎的做法是避免更改正在迭代的列表。考虑代码
您可能会惊讶地发现,此打印件
在 for 循环期间,Python 使用在每次迭代结束时递增的内部计数器来跟踪它在列表中的位置。当计数器的值达到列表的当前长度时,循环终止。如果列表在循环中不会发生突变,但如果列表发生突变,可能会产生令人惊讶的后果。在这种情况下,隐藏的计数器从o开始,发现L1[0]在L2中,并删除它 - 将L1的长度减少到3。然后计数器递增到 1,代码继续检查 L1[1] 的值是否在 L2 中。请注意,这不是L1[1]的原始值(即2),而是L1[1]的当前值(即3)。如您所见,可以弄清楚在循环中修改列表时会发生什么。但是,这并不容易。发生的事情很可能是无意的,就像这个例子一样。
避免此类问题的一种方法是使用切片来克隆35(即复制)列表并在L1[:]中写入el。请注意,编写
不会解决问题。它不会创建L1的副本,而只是为现有列表引入一个新名称。
切片并不是在Python中克隆列表的唯一方法。表达式 L.copy() 与 L[:] 具有相同的值。切片和复制都执行所谓的浅层复制。浅层副本创建一个新列表,然后将要复制到新列表中的列表的对象(不是对象的副本)插入到新列表中。代码
打印 L1=[[2, 3]] L2 = [[2, 3]],因为 L1 和 L2 都包含在第一个赋值语句中绑定到 L 的对象。
如果要复制的列表包含还要复制的可变对象,请导入标准库模块副本并使用功能 copy. deepcopy 创建深层副本。该方法 deepcopy 创建一个新列表,然后将列表中要复制到新列表中的对象的副本插入到新列表中。如果我们用L2 = copy.deepcopy(L1)替换上面代码中的第三行,它将打印L1 =[[2, 3]], L2= [[2]],因为L1不包含L绑定到的对象。
如果列表的元素是包含列表(或任何可变类型)的列表,则理解副本深度复制是很棘手的。考虑
L3 的值将是 [[[2]]],因为 copy.deepcopy 不仅为列表 [L1] 创建一个新对象,还为列表 L1 创建新对象。也就是说,它大部分时间都会一直复制到底部。为什么是“大多数时候”?代码
创建一个包含自身的列表。一直到底部的复制尝试永远不会结束。若要避免此问题,copy.deepcopy 只创建每个对象的一个副本,然后将该副本用于该对象的每个实例。即使列表不包含自身,这也很重要。例如
打印 [[2, 3], [2, 3]],因为 copy.deepcopy 会生成 L1 的一个副本,并在 L2 中出现 L1 时同时使用它。