Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python objects confusion: a=b, modify b and a changes! [duplicate]

I thought i knew Python until tonight. What is the correct way to do something like this? Here's my code:

a = ["one", "two", "three"]
b = a  # here I want a complete copy that when b is changed, has absolutely no effect on a
b.append["four"]
print a  # a now has "four" in it

Basically i want to know, instead of the b = a step, how would I correctly make a copy of a list or dictionary so that when b is changed a does not change along with it?

like image 437
james Avatar asked Jan 03 '11 20:01

james


3 Answers

What you are experiencing is the concept of references. All objects in Python have a reference and when you assign one to two names a and b, this results in both a and b pointing to the same object.

>>> a = range(3)
>>> b = a                     # same object
>>> b.append(3)
>>> a, b                      # same contents
([0, 1, 2, 3], [0, 1, 2, 3])

With lists, you can make create a new list b that is a copy of another a using b = a[:].

>>> a = range(3)
>>> b = a[:]                  # make b a new copy of a
>>> b.append(3)
>>> a, b                      # a is left unchanged
([0, 1, 2], [0, 1, 2, 3])

For a more general solution for any object, use the copy module. A shallow copy will copy the references stored within the object you're copying, whereas a deep copy will recursively make new copies of all objects.

>>> a = [range(2), range(3)]
>>> b = copy.copy(a)          # shallow copy of a, equivalent to a[:]
>>> b[0] = range(4)
>>> a, b                      # setting an element of b leaves a unchanged
([[0, 1], [0, 1, 2]], [[0, 1, 2, 3], [0, 1, 2]])
>>> b[1].append(3)
>>> a, b                      # modifying an element of b modifies the element in a
([[0, 1], [0, 1, 2, 3]], [[0, 1, 2, 3], [0, 1, 2, 3]])

>>> a = [range(2), range(3)]
>>> b = copy.deepcopy(a)      # deep recursive copy of a
>>> b[1].append(3)
>>> a, b                      # modifying anything in b leaves a unchanged
([[0, 1], [0, 1, 2]], [[0, 1], [0, 1, 2, 3]])
like image 112
moinudin Avatar answered Sep 28 '22 14:09

moinudin


The correct way of copying an object is

 from copy import copy
 a = [1, 2, 3]
 b = copy(a)

Pretty simple. There is shortcuts for lists:

 a = [1, 2, 3]
 b = a[:]

There is also deepcopy() if you want to copy the objects in the list as well.

like image 29
Lennart Regebro Avatar answered Sep 28 '22 14:09

Lennart Regebro


Here are 3 ways to make a copy of list a:

Use slice notation:

copy_of_a = a[:]

Use the list constructor:

copy_of_a = list(a)

Use the copy module:

from copy import copy
copy_of_a = copy(a)

These are all shallow copies, which is sufficient for your question. To learn about the difference between shallow copy and deep copy read the documentation of the copy module.

like image 34
Steven Rumbalski Avatar answered Sep 28 '22 14:09

Steven Rumbalski