9

I am aware that if I wish to delete only the first element of a list t in Python I can do it with :

del t[0]

which is about as straightforward as it gets. However :

t = t[1:]

also works. In the textbook that I am learning from it says it is generally considered bad practice to use the latter approach since it does not delete the head of the list per se but

"The slice operator creates a new list and the assignment makes t refer to it, but none of that has any effect on the list that was passed as an argument."

Why is this bad ? Can you name an example where such an approach would significantly alter a function ? Thanks in advance.

  • 1
    If *what you specifically want to do* is to remove the first element from the list, using an approach that doesn't do that is bad practice. That doesn't mean that `t = t[1:]` is bad practice in general. – user2357112 Mar 26 '17 at 06:28
  • In addition, you can modify the original list with `t[:] = t[1:]`. – TigerhawkT3 Mar 26 '17 at 06:28
  • 1
    There are plenty of cases where either `del t[0]` or `t = t[1:]` would be fine, and plenty of cases where `del t[0]` would be wrong and `t = t[1:]` would be appropriate. – user2357112 Mar 26 '17 at 06:29
  • You can use `t.pop(0)`, this will return value of first element and remove it from list. – darvark Mar 26 '17 at 06:31
  • 1
    @darvark - OP isn't asking for other ways to remove an item from a list, they're asking about use cases for modifying the original list vs creating a new one. – TigerhawkT3 Mar 26 '17 at 06:32

3 Answers3

6

There are multiple reasons this is not a good idea:

  • Creating a new list just makes unnecessary work making the new list and deallocating the old list. And in between the two steps, twice the memory is used (because the original list and new list are alive at the same time, just prior to the assignment).

  • If something else refers to the same list, it does not get updated: u = t; del t[0] changes both u and t. But u = t; t = t[1:] assigns the new list to t while leaving u unchanged.

  • Lastly, del t[0] is clearer about its intension to remove the element than the more opaque t = t[1:].

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • I suppose that `t[:] = t[1:]` _could_ be used to mutate the existing list object, but it has to do roughly twice the work of `del t[0]`, since the `del` operation only has to move all the subsequent list items down, whereas `t[1:]` has to copy the subsequent items to a new list, and then copy them back to the original list object. Is that correct? – PM 2Ring Mar 28 '17 at 10:49
2

Consider a function with the two implementations:

def remove_first_a(t):
    t = t[1:]  

def remove_first_b(t):
    del t[0]

Now, see those functions in use:

> l = [1, 2, 3]
> remove_first_a(l)
> l
[1, 2, 3]
> remove_first_b(l)
> l
[2, 3]

The first implementation only reassigns the local variable t which has no effect on the object that was passed as a parameter. The second implementation actually mutates that object. The first function is rather useless in its present shape. You could change it:

def remove_first_a(t):
    return t[1:] 

> l = [1, 2, 3]
> x = remove_first_b(l)
> x
[2, 3]

Whether you want one or the other, depends more on the actual use case. Sometimes you want the original list to still be around unchanged for later use, and sometimes you want to make sure the original gets changed in all places that still have a reference to it.

user2390182
  • 72,016
  • 6
  • 67
  • 89
1

just a example for the del and slice.

In [28]: u = t = [1, 2,3,4]
In [30]: id(u) == id(t)   # now the id is same,they point one obj
Out[30]: True

if we use the del operator.

In [31]: del t[0]
In [32]: t
Out[32]: [2, 3, 4]
In [33]: u
Out[33]: [2, 3, 4]

but if we use the slice operator.

In [35]: t = t[1:]
In [36]: t
Out[36]: [2, 3, 4]
In [37]: id(t) == id(u)
Out[37]: False
In [39]: u
Out[39]: [1, 2, 3, 4]

and we found that t and u point different obj now.so we deal the list t, the list u is not change.

IkarosKun
  • 463
  • 3
  • 15