206

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' ?"

0

11 Answers 11

290

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[:]
Sign up to request clarification or add additional context in comments.

6 Comments

Doesn't work for me. Any changes I make to b are also seen in a.
@Mannix Can you post the full code you have which shows the problem (i.e. an assertion should fail) in a new question? Most likely, you're not modifying the list itself, but its elements. Create a deep copy if you want a new list whose elements are copies as well.
However, if a is a 2-dimensional list, this is not going to work
For 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))
@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.
|
170

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]]
>>> 

1 Comment

what 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?
44

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

6 Comments

Thank you for bringing performance into the discussion, this helped me to make a decision about which method to use.
I'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.
I 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)
Test case for extend() call is not comparable to others. To use extend() you must create an array first while other constructs will create an array for you. So you effectively giving extend() an advantage by skipping initialization of the list object. To correct the test move b = [] from setup to a statement under the test, like b = []; b.extend(a). This will change results in favor of second case which uses slicing to create a copy.
Why does b=list(a) take twice as long as b=a[:] ?
|
19

Also, you can do:

b = list(a)

This will work for any sequence, even those that don't support indexers and slices...

1 Comment

note 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
17

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))]

1 Comment

not 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
16

As mentioned by phihag in his answer,

b = a[:]

will work for your case since slicing a list creates a new memory id of the list (meaning you are no longer referencing the same object in your memory and the changes you make to one will not be reflected in the other.)

However, there is a slight problem. If your list is multidimensional, as in lists within lists, simply slicing will not solve this problem. Changes made in the higher dimensions, i.e. the lists within the original list, will be shared between the two.

Do not fret, there is a solution. The module copy has a nifty copying technique that takes care of this issue.

from copy import deepcopy

b = deepcopy(a)

will copy a list with a new memory id no matter how many levels of lists it contains!

2 Comments

Great answer, Jordan! Thanks!!! Do you know the reason for this?
Great 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() ).
6

When you do b = a you simply create another pointer to the same memory of a, that's why when you append to b , a changes too.

You need to create copy of a and that's done like this:

b = a[:]

1 Comment

Just 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 by a.
5

To create a copy of a list do this:

b = a[:]

Comments

3

I found that we can use extend() to implement the function of copy()

a=['help', 'copyright', 'credits', 'license']
b = []
b.extend(a)
b.append("XYZ") 

Comments

2

I would recommend the following solution:

b = []
b[:] = a

This will copy all the elements from a to b. The copy will be value copy, not reference copy.

1 Comment

This is not better than b = a[:]
1

b = list(a)

See http://henry.precheur.org/python/copy_list.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.