一、直接看坑
def remove_list(item, n):
for i in item:
if i == n:
item.remove(i)
if __name__ == '__main__':
origin_list = [1, 2, 3, 3, 3, 4]
print('before remove : ', origin_list)
remove_list(origin_list, 3)
print('after remove : ', origin_list)
before remove : [1, 2, 3, 3, 3, 4]
after remove : [1, 2, 3, 4]
定义的函数是删除列表中为3的元素,结果却并没有完全删除列表中为3的元素,why?
二、原因
For in 是对下标进行遍历操作,remove()是对值进行操作;
Python中,list 属于线性表,用一块连续的内存空间存储元素,调用 remove()函数 删除指定元素时,会删除内存地址中的元素,删除指定元素后,后面所有元素会自动向前移动一个位置;
本例列表中,第1个3的下标为2,当删除第1个3后,后面所有元素会自动向前移动一个位置,即第2个3的下标变成了2,因为 For in 已经遍历过 下标为2,循环遍历时,会自动跳过第2个3;
使用list.pop()函数删除指定元素的时候,也存在上述的坑。
三、概念延伸
浅拷贝:在复制的时候只增加了一个指针,没有为其分配内存空间,即一个列表 a, a 里的值都有指向自己的指针,而且也有自己的内存空间a1,浅拷贝列表 a 得到一个列表A,A里的值都有指向自己的指针,但是其内存空间还是a1,无论是对 a 还是 A 进行操作,都会改变内存空间a1里的值;
深拷贝:在复制的时候不但增加了一个指针,而且还为其分配了内存空间,即一个列表 a, a 里的值都有指向自己的指针,而且也有自己的内存空间a1,深拷贝列表 a 得到一个列表A,A里的值都有指向自己的指针,而且也有自己的内存空间A1,操作时,可以去 a 里查找,在 A 里操作,由于都有自己独立的内存空间,不会相互影响。就可以避免遗漏值,出现错误。
四、解决方案
- 深拷贝列表
import copy
a = [1, 2, 3, 3, 3, 4]
b = copy.deepcopy(a)
for i in a:
if i == 3:
b.remove(i)
print(b)
[1, 2, 4]
- while判断
c = [1, 2, 3, 3, 3, 4]
while 3 in c:
c.remove(3)
print(c)
[1, 2, 4]
- 列表推导式
d = [1, 2, 3, 3, 3, 4]
new_d = [i for i in d if i != 3]
print(new_d)
[1, 2, 4]
- 倒序遍历:巧妙避坑
e = [1, 2, 3, 3, 3, 4]
for i in e[::-1]:
if i == 3:
e.remove(i)
print(e)
[1, 2, 4]
PS :删除列表中指定元素时,建议不要使用 for 循环。