Python切片、列表赋值与深浅拷贝相关技术问题咨询
问题背景与疑问
需实现从L1中移除所有在L2中存在的元素,以下为两种实现代码、运行输出及两点疑问:
- 第二种案例为何能正常运行?我推测切片(slicing)生成L1的浅拷贝(shallow copy)后,循环的隐藏计数器会忽略元素2——因为L1首个元素被移除后,2处于索引0,但为何循环仍能访问该元素?我预期的输出如下(附预期输出)。
- 第一种案例中,L1移除元素后L3为何仍保持初始列表状态?代码
L3 = L1[:]的机制是什么?是深拷贝(deep copy)吗?我原以为只是浅拷贝。
案例一代码
def removeDups(L1, L2): L3 = L1[:] for e1 in L3: print('L3' + str(L3)) print('L1: ' + str(L1)) if e1 in L2: L1.remove(e1) L1 = [1,2,3,4] L2 = [1,2,5,6] removeDups(L1, L2)
案例一输出
L3[1, 2, 3, 4] L1: [1, 2, 3, 4] L3[1, 2, 3, 4] L1: [2, 3, 4] L3[1, 2, 3, 4] L1: [3, 4] L3[1, 2, 3, 4] L1: [3, 4]
案例二代码
def removeDups(L1, L2): for e1 in L1[:]: print('L1[:]: ' + str(L1[:])) print('L1: ' + str(L1)) if e1 in L2: L1.remove(e1) L1 = [1,2,3,4] L2 = [1,2,5,6] removeDups(L1, L2)
案例二输出
L1[:]: [1, 2, 3, 4] L1: [1, 2, 3, 4] L1[:]: [2, 3, 4] L1: [2, 3, 4] L1[:]: [3, 4] L1: [3, 4] L1[:]: [3, 4] L1: [3, 4]
案例二预期输出
L1[:]: [1, 2, 3, 4] L1: [1, 2, 3, 4] L1[:]: [2, 3, 4] L1: [2, 3, 4] L1[:]: [2, 3, 4] L1: [2, 3, 4]
问题解答
疑问1:第二种案例为何能正常运行?
你混淆了循环迭代的对象——案例二中,for e1 in L1[:]的迭代对象是循环开始前就生成的L1的浅拷贝,而非动态变化的L1本身。
初始时L1[:]生成的拷贝是[1,2,3,4],循环会依次遍历这个拷贝里的每一个元素:1、2、3、4。
- 第一次迭代:取元素1,发现它在L2中,移除L1的1,此时L1变成
[2,3,4]; - 第二次迭代:取拷贝里的元素2,此时L1中仍存在2,所以移除它,L1变成
[3,4]; - 第三、四次迭代:取拷贝里的3和4,都不在L2中,无操作。
你预期输出错误的核心原因是误以为循环在遍历动态的L1,但实际上迭代器基于初始拷贝创建,不会受L1后续修改的影响,因此不会“跳过”元素2。
疑问2:案例一中L3为何不随L1变化?L3 = L1[:]是深拷贝吗?
L3 = L1[:]确实是浅拷贝,但它创建了一个独立的新列表对象——列表里的元素和L1共享(若元素为可变对象),但列表本身和原L1是两个完全分开的对象。
案例一中,L3是循环开始前L1的完整拷贝,后续对L1的元素移除操作仅修改L1自身,不会影响L3的内容。因为L3是独立的列表,即便元素是整数这类不可变对象,原列表的修改也不会传递到拷贝后的列表上。这和浅拷贝的机制完全一致,浅拷贝仅复制列表结构,不复制元素本身,但列表对象本身是新的,所以原列表的修改不会波及拷贝。
内容的提问来源于stack exchange,提问作者HugoWang
相关产品推荐
相关产品推荐

