10

I'm trying to implement a function 'add' that combines the list L1 with L2 into L3:

def add(L1,L2,L3):
    L3 = L1 + L2

L3 = []
add([1],[0],L3)
print L3

The code above produces an empty list as a result instead of [1,0] - This means that L3 wasn't passed by reference.

How to pass L3 by reference?

Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
user6039980
  • 3,108
  • 8
  • 31
  • 57

4 Answers4

21

Lists are already passed by reference, in that all Python names are references, and list objects are mutable. Use slice assignment instead of normal assignment.

def add(L1, L2, L3):
    L3[:] = L1 + L2

However, this isn't a good way to write a function. You should simply return the combined list.

def add(L1, L2):
    return L1 + L2

L3 = add(L1, L2)
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
chepner
  • 497,756
  • 71
  • 530
  • 681
  • 2
    "Use slice assignment instead of normal assignment." So why does normal assignment not work? – caylus Apr 27 '21 at 10:03
  • 2
    Because `L1 + L2` creates a new list object which gets assigned to `L3`, rather than replacing the *elements* of the list that `L3` already refers to. In many cases it may not matter, but the OP is specifically asking about a scenario where they expect an existing list to be updated. – chepner Apr 27 '21 at 13:03
  • so L3 (the reference to the list L3) is being passed by value, not by reference, and that's why you can't directly change L3 -the reference- inside the function, instead having to do a "slice assignment" (so not having to change L3) ? :P How elegant is C++ in that regard. – German Garcia Sep 07 '21 at 22:31
  • 1
    The function has little to do with it. `L3 = ...` *never* has anything to do with whatever `L3` currently refers to. – chepner Sep 07 '21 at 23:27
5

You can achieve this with:

L3[:] = L1 + L2

Test Code:

def add(L1, L2, L3):
    L3[:] = L1 + L2

L3 = []
add([1], [0], L3)
print(L3)

Results:

[1, 0]
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
4

If you want changes to be made inplace, you'd need to perform operations that modify the list inplace. This would mean any of the list instance methods. In this particular instance, you could look at list.extend.

def add(L1, L2, L3):
    L3.extend(L1 + L2)   # creates a new list object and copies it into L3

Since this creates a an copy (which may be inefficient), you can instead use two extend calls in its place -

def add(L1, L2, L3):
    L3.extend(L1)        
    L3.extend(L2)

Calling L3.extend modifies the original list in place. With your current code, L1 + L2 creates a new list, and re-assigns L3 to that object (and the original object that L3 was referring to was not touched).


If you'd like to generalise this to any number of lists, I'd recommend taking a look at using variable arguments:

from itertools import chain

def add(L3, *L):
    L3.extend(chain.from_iterable(L))

Here's an example of how it works:

>>> L3 = []
>>> add(L3, [1], [2], [3])
>>> L3
[1, 2, 3]

As a matter of good practice, you should either

  • define a function that does not modify the original structure, but returns a new value you can assign from the caller, OR
  • define a function that modifies structures in place, and returns nothing.

Another user note: L3[:] = ... will replace L3 of all its previous contents with the items from L1 + L2. On the other hand, L3.extend(...) will not destroy what was previously in L3, but is instead extended by what it is passed. I'd recommend evaluating your use case and using the more appropriate method to the situation.

However, to cater to that case, you can build on the accepted answer's method using inplace assignment with __setitem__:

def add(L3, *L):
    L3[:] = chain.from_iterable(L)

Which works the same way, and should be very efficient for many lists.

cs95
  • 379,657
  • 97
  • 704
  • 746
1

You can't explicitly pass a variable by reference in Python, but you can update properties on existing objects.

Therefore, what you can do is update values on L3, all of them in your case, so you could do it like this:

def add(L1 ,L2, L3):
    L3[:] = L1 + L2

L3 = []

add([1], [0], L3)

print L3
Danziger
  • 19,628
  • 4
  • 53
  • 83