python list by value not by reference
Solution 1
You cannot pass anything by value in Python. If you want to make a copy of a
, you can do so explicitly, as described in the official Python FAQ:
b = a[:]
Solution 2
To copy a list you can use list(a)
or a[:]
. In both cases a new object is created.
These two methods, however, have limitations with collections of mutable objects as inner objects keep their references intact:
>>> a = [[1,2],[3],[4]]
>>> b = a[:]
>>> c = list(a)
>>> c[0].append(9)
>>> a
[[1, 2, 9], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>> b
[[1, 2, 9], [3], [4]]
>>>
If you want a full copy of your objects you need copy.deepcopy
>>> from copy import deepcopy
>>> a = [[1,2],[3],[4]]
>>> b = a[:]
>>> c = deepcopy(a)
>>> c[0].append(9)
>>> a
[[1, 2], [3], [4]]
>>> b
[[1, 2], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>>
Solution 3
In terms of performance my favorite answer would be:
b.extend(a)
Check how the related alternatives compare with each other in terms of performance:
In [1]: import timeit
In [2]: timeit.timeit('b.extend(a)', setup='b=[];a=range(0,10)', number=100000000)
Out[2]: 9.623248100280762
In [3]: timeit.timeit('b = a[:]', setup='b=[];a=range(0,10)', number=100000000)
Out[3]: 10.84756088256836
In [4]: timeit.timeit('b = list(a)', setup='b=[];a=range(0,10)', number=100000000)
Out[4]: 21.46313500404358
In [5]: timeit.timeit('b = [elem for elem in a]', setup='b=[];a=range(0,10)', number=100000000)
Out[5]: 66.99795293807983
In [6]: timeit.timeit('for elem in a: b.append(elem)', setup='b=[];a=range(0,10)', number=100000000)
Out[6]: 67.9775960445404
In [7]: timeit.timeit('b = deepcopy(a)', setup='from copy import deepcopy; b=[];a=range(0,10)', number=100000000)
Out[7]: 1216.1108016967773
Solution 4
Also, you can do:
b = list(a)
This will work for any sequence, even those that don't support indexers and slices...
Solution 5
If you want to copy a one-dimensional list, use
b = a[:]
However, if a
is a 2-dimensional list, this is not going to work for you. That is, any changes in a
will also be reflected in b
. In that case, use
b = [[a[x][y] for y in range(len(a[0]))] for x in range(len(a))]
Related videos on Youtube
d.putto
Updated on March 19, 2021Comments
-
d.putto about 3 years
Let's take an example
a=['help', 'copyright', 'credits', 'license'] b=a b.append('XYZ') b ['help', 'copyright', 'credits', 'license', 'XYZ'] a ['help', 'copyright', 'credits', 'license', 'XYZ']
I wanted to append value in list 'b' but the value of list 'a' have also changed.
I think I have little idea why its like this (python passes lists by reference).
My question is "how can I pass it by value so that appending 'b' does't change values in 'a' ?"-
Rezaul Karim Shaon about 2 yearsb = a.copy() , this way it will work.
-
-
Kyle Pittman about 8 yearsThank you for bringing performance into the discussion, this helped me to make a decision about which method to use.
-
AsheKetchum about 7 yearswhat is the difference between a regular copy and a deep copy? Why does what happens above happen? I think I have a general understanding, it seems to be like the same problem encountered by the op at the second layer. How does it work internally?
-
Felipe about 7 yearsGreat answer, Jordan! Thanks!!! Do you know the reason for this?
-
Mannix almost 7 yearsDoesn't work for me. Any changes I make to
b
are also seen ina
. -
phihag almost 7 years
-
Artur almost 7 yearsI've just found your answer, thank you for this high quality reply! When discussing Python often performance isn't considered and for huge data sets it makes difference.
-
Eran Yogev over 6 yearsI like this answer, however, it doesn't relate to the values of the list. As Jordan Pagni mentioned, if your list is multidimensional, as in lists within lists (and more), then the only solution that will work is the one that takes the longest time: b = deepcopy(a)
-
Kyr over 6 years@EranYogev, I agree. If you want to achieve performance though you have to have some knowledge about your list's contents. :(
-
Mr. Deathless over 6 yearsTest case for
extend()
call is not comparable to others. To useextend()
you must create an array first while other constructs will create an array for you. So you effectively givingextend()
an advantage by skipping initialization of the list object. To correct the test moveb = []
from setup to a statement under the test, likeb = []; b.extend(a)
. This will change results in favor of second case which uses slicing to create a copy. -
AruniRC about 6 yearsGreat answer, especially as it mentions both the case where the initial solution will fail (nested objects, a list of other objects) and the solution ( deepcopy() ).
-
Pythoner almost 6 yearsHowever, if a is a 2-dimensional list, this is not going to work
-
Pythoner almost 6 yearsFor 2D arrays it's possible use map function: old_array = [[2, 3], [4, 5]] # python2.* new_array = map(list, old_array) # python3.* new_array = list(map(list, old_array))
-
phihag almost 6 years@Pythoner The code you describe works for 2D lists, not arrays.
copy.deepcopy(something)
works for both. But then again, if your list is 2D - or any data structure but a simple list - then you have a different question than the one here. -
scherm over 5 yearsWhy does
b=list(a)
take twice as long asb=a[:]
? -
Endyd almost 5 yearsJust a technicality, but python variables are not really pointers. It would be more accurate to say when you do
b = a
you create another reference to the list object referenced bya
. -
Endyd almost 5 yearsThis is not better than
b = a[:]
-
Dmitry Polovinkin over 2 yearsBut know that in that case if you have a list inside of
a
, and if you change it inb
, it will also change ina
. But integers or strings will not be changed. That's what is meant by multidimensional lists mentions -
Dmitry Polovinkin over 2 yearsnote that this approach will also not fully work with multidimensional lists - so if you have a list in original list, it will change everywhere if changed in one copy
-
Dmitry Polovinkin over 2 yearsnot really the case that any changes will be reflected - only if list inside the original list is changed it will reflect on the copy. Other data changes will not be reflected on other copy, so strings or integers are safe to change