1

It is believed that lists in python as a mutable object are passed by reference. However when I try to change the list passed to a function to be assigned by another list, particularly empty list, the change is not observable in the caller.

Giving more details here is my code:

def callee(l):
  l = list() # this could be any list but my interest was empty list

def caller():
  l = [1, 2, 3]
  caller(l)
  print(l) # prints [1, 2, 3] while I expect an empty list

How can I remove all elements of a list in the callee function?

When I change one particular element of a list in the callee, it is observable in the caller. What kind of passing is this, call-by-value or call-by-reference? I believe neither and I appreciate any clarification on this too.

martineau
  • 119,623
  • 25
  • 170
  • 301
masec
  • 584
  • 5
  • 16
  • [This answer](https://stackoverflow.com/a/986145/6625815) may cover what you're looking for. – Andrew F Dec 23 '18 at 19:59
  • 6
    A highly recommended read https://nedbatchelder.com/text/names.html The issue is that "assignments" override whatever you had sent previously. If you wish to mutate the original object, you have to use the object's methods, such as `l.clear()` – Paritosh Singh Dec 23 '18 at 20:02

3 Answers3

4

You are just reassigning a local variable in the scope of callee. So, just change the content of that list instead:

def callee(l):
  l[:] = list()
  # or l.clear()
Netwave
  • 40,134
  • 6
  • 50
  • 93
3

You're changing the reference, instead of modifying the object referenced to. To see a difference, you need to actually change the object you pass by reference:

def callee(l):
    while len(l) > 0:
        l.pop()



def caller():
    l = [1, 2, 3]
    callee(l)
    print(l) # prints [] 
Yakov Dan
  • 2,157
  • 15
  • 29
1

Each time you use the = operator you are changing the object the variable is pointing to.

When you type

l = [1, 2, 3]

A python list is created in memory, and a reference in the scope of caller() named l is now pointing to this newly created list.

However, when the callee() function is called, another list is created in memory and now it has one reference in the scope of callee() pointing to it.

So now we have 2 lists in memory (and not one) each with its own reference pointer (named l in both cases but in different scopes). When callee() returns, the reference to the second list expires and the object now has no more pointers pointing to it, so the garbage collector deletes it from memory. The original list is left unchanged.

To clear the list up, you can use l.clear(). Since you didn't use the = operator, no new object is created in memory and you can be sure that you are pointing to the same old object.

Peter Emil
  • 573
  • 3
  • 13