4

I am trying to write a function which removes the first item in a Python list. This is what I've tried. Why doesn't remove_first_wrong change l when I call the function on it? And why does the list slicing approach work when I do it in the main function?

def remove_first_wrong(lst):
    lst = lst[1:]

def remove_first_right(lst):
    lst.pop(0)

if __name__ == '__main__':
    l = [1, 2, 3, 4, 5]
    remove_first_wrong(l)
    print(l)

    l_2 = [1, 2, 3, 4, 5]
    remove_first_right(l_2)
    print(l_2)

    # Why does this work and remove_first_wrong doesn't?
    l_3 = [1, 2, 3, 4, 5]
    l_3 = l_3[1:]
    print(l_3)
Akshay Hazari
  • 3,186
  • 4
  • 48
  • 84
Asic Chen
  • 43
  • 2
  • 1
    possible duplicate of http://stackoverflow.com/questions/4426663/how-do-i-remove-the-first-item-from-a-python-list – pigletfly Dec 06 '15 at 01:39
  • @pigletfly: with some names-are-references confusion mixed in. – Martijn Pieters Dec 06 '15 at 01:40
  • It's better to return values instead of in-place coding, it allows for more dynamically-typed, short code with less temporary variables. –  Dec 06 '15 at 02:11

3 Answers3

8

Slicing a list returns a new list object, which is a copy of the original list indices you indicated in the slice. You then rebound lst (a local name in the function) to reference that new list instead. The old list is never altered in that process.

list.pop() on the other hand, operates on the list object itself. It doesn't matter what reference you used to reach the list.

You'd see the same thing without functions:

>>> a = [1, 2]
>>> b = a[:]  # slice with all the elements, produces a *copy*
>>> b
[1, 2]
>>> a.pop()  # remove an element from a won't change b
2
>>> b
[1, 2]
>>> a
[1]

Using [:] is one of two ways of making a shallow copy of a list, see How to clone or copy a list?

You may want to read or watch Ned Batchelder's Names and Values presestation, to further help understand how Python names and objects work.

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2

Inside the function remove_first_wrong the = sign reassigns the name lst to the object on the right. Which is a brand new object, created by slicing operation lst[1:]. Thus, the object lst assigned to is local to that function (and it actually will disappear on return).

That is what Martijn means by "You then rebound lst (a local name in the function) to reference that new list instead."

On contrary, lst.pop(0) is a call to the given object -- it operates on the object.

For example, this will work right too:

def remove_first_right2(lst):
    x = lst  # x is assigned to the same object as lst
    x.pop(0) # pop the item from the object
xealits
  • 4,224
  • 4
  • 27
  • 36
1

Alternately, you can use del keyword:

def remove_first_element(lst):
   del lst[0]
   return lst
AimZ
  • 11
  • 2