问题背景:
append(list)与append(list[:])的区别
append(list)
执行list2.append(list1)时,实际上是将list1列表的引用添加到了list2中。
意味着,list2列表中的元素与list1列表指向同一个对象;
因此,在对list1进行就地修改操作修改list1时,修改便反馈在list2上。
当然,如果对list1进行的是非就地修改操作,list2结果并不会受到影响。
list1 = [1, 2, 3] list2 = [] # 添加list1的引用 list2.append(list1) # 现在,list2和list1 都指向同一个列表 print(list2) # 输出: [[1, 2, 3]] # 修改list1 list1.append(4) # list2中的元素也被修改了,因为它们指向同一个列表 print(list2) # 输出: [[1, 2, 3, 4]]
append(list[:])
执行list2.append(list1[:])时,实际上创建了一个list1列表的浅拷贝,并将这个浅拷贝的引用添加到list2中。
意味着,list2中的元素是一个新列表,与list1在内存中占有不同的位置;
# 添加list1的浅副本 list2.append(list1[:]) # 现在,res和path指向不同的列表 print(list2) # 输出: [[1, 2, 3]] # 修改list1 list1.append(4) # list2中的元素没有改变,因为它们是独立的列表 print(list2) # 输出: [[1, 2, 3]]
就地修改与非就地修改的区别
刚才有提到就地修改和非就地修改的说法,到底何为列表的就地修改?何为非就地修改呢?
非就地修改(Non-in-place Modification)
创建原始数据的一个新副本,并在该副本上进行修改,而原始数据保持不变。
常见操作:
1、切片复制新变量
original = [1, 2, 3] modified = original[:] # 浅拷贝 modified.append(4) # 修改新列表,原始列表不变
2、列表推导式
original = [1, 2, 3, 4, 5] modified = [x * 2 for x in original] # 创建新列表,每个元素都是原始元素的两倍
3、
map()
或filter()
函数original = [1, 2, 3, 4, 5] modified = list(map(lambda x: x * 2, original)) # 每个元素乘以2 print(modified) # 输出:[2, 4, 6, 8, 10]filtered_iter = filter(lambda x: x > 3, original) # filter()返回的是一个迭代器,因此我们需要将它转换成列表或其他数据结构来查看结果 filtered_list = list(filtered_iter) print(filtered_list) # 输出: [4, 5]
4、列表的
+
操作符list1 = [1, 2, 3] list2 = [4, 5, 6] combined = list1 + list2 # 合并成新列表
就地修改(In-place Modification)
直接修改原始数据,不会创建新的数据副本。
常见操作:
1、append()、pop()、remove()、insert()、sort()、reverse()等直接修改列表本身的方法
2、切片赋值
list1 = [1, 2, 3, 4, 5] list1[1:3] = [20, 30] # 直接替换列表中的一部分
3、
__setitem__
特殊方法这不是日常编程中常用的方法,但它是Python中所有可变序列类型(如列表)支持的就地修改机制的一部分。
my_list = [1, 2, 3] my_list.__setitem__(1, 10) # 直接设置索引为1的元素为10