python基础–del操作

list中remove和del的区别

#remove删除首个符合条件的元素,并不删除特定的索引
l1 = [1,1,1,2,3,4,5,5]
l1.remove(2)
print(l1)  #[1, 1, 1, 3, 4, 5, 5]

#del按照索引删除字符
l2 = [1,1,1,2,3,4,5,5]
del l2[2]
print(l2)  #[1, 1, 2, 3, 4, 5, 5]

del用法

#del 除可以删除单个元素,还可以删除指定范围内的值和整个对象
l = [1,1,1,2,3,4,5,5]
del l[2:5]
print(l)  #[1, 1, 4, 5, 5]

del l
print(l)  # NameError: name 'l' is not defined

Python中del和垃圾回收

Python语言默认采用的垃圾回收机制是引用计数法,当一个对象的引用计数为0时, Python的垃圾回收机制就会将对象回收。
del语句作用在变量上,而不是数据对象上。也就是说在python中, del语句删除某个对象时, 并不是直接将该对象在内存中删除, 而是将该对象的引用计数-1。下面还是以例子来说,

li = [1,2,3,4,5] #定义列表,列表本身不包含数据1-5,而是包含变量li[0] li[1] li[2] li[3] li[4]  
first = li[0]    #这相当于浅拷贝,first指向了li[0]
print(id(li))    #li的地址,例为2376828968620
print(id(li[0])) #其中的li[0]地址为141721836406800
print(id(first)) #first地址141721836406800,说明其与li[0]指向一样

del li[0]        #删除li[0],实际是引用计数-1

print(id(li))    #li地址不变,仍为2376828968620
print(id(li[0])) #此时li[0]地址为141721836406832,因为最初指向0的引用-1了,而新的li[0]出现了,该值为2
print(id(first)) #first指向1,所以其地址不变

print(li)        #[2, 3, 4, 5]
print(first)     #值为1

拓展

最初想详细研究remove和del是因为leetcode上的一道数组问题,leetcode283。使用删除非0元素的思路,remove结果正确,而del结果错误。

class Solution(object):
    def moveZeroes(self, nums):
        if not nums: return []
        for i in range(len(nums)):
            if nums[i] == 0:
                nums.remove(nums[i])
                nums.append(0)
        return nums

为什么会这样,以nums=[1,0,0,3]为例。如果为remove,其流程为:

  1. i==0,nums[0]为1,不为0,到下一个循环;
  2. i==1,nums[1]为0,为0,remove删除首个符合条件的元素,结果为[1,0,3],添加0后为[1,0,3,0];
  3. i==2,nums[2]为1,不为0,到下一个循环;
  4. i==3,nums[3]为0,为0,remove删除首个符合条件的元素,结果为[1,3,0],添加0后为[1,3,0,0]。
for i in range(len(nums)):
    if nums[i] == 0:
        del nums[i]
        nums.append(0)

如果为del,以nums=[1,0,0,3]为例,其流程为:

  1. i==0,nums[0]为1,不为0,到下一个循环;
  2. i==1,nums[1]为0,为0,del按索引删除,结果为[1,0,3],添加0后为[1,0,3,0];
  3. i==2,nums[2]为1,不为0,到下一个循环;
  4. i==3,nums[3]为0,为0,del按索引删除nums[3],结果为[1,0,3],添加0后为[1,0,3,0]。

不过该题还是建议使用双指针。因为list中remove的时间复杂度为O(n)。