Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why deepcopy of list of integers returns the same integers in memory?

I understand the differences between shallow copy and deep copy as I have learnt in class. However the following doesn't make sense

import copy

a = [1, 2, 3, 4, 5] 

b = copy.deepcopy(a)

print(a is b)
print(a[0] is b[0])
----------------------------
~Output~
>False
>True
----------------------------

Shouldn't print(a[0] is b[0]) evaluate to False as the objects and their constituent elements are being recreated at a different memory location in a deep copy? I was just testing this out as we had discussed this in class yet it doesn't seem to work.

like image 222
Gerald Lee Avatar asked Jul 25 '15 01:07

Gerald Lee


People also ask

What is the difference between copy copy and copy Deepcopy functions applicable to a list or dictionary in Python?

copy() create reference to original object. If you change copied object - you change the original object. . deepcopy() creates new object and does real copying of original object to new one. Changing new deepcopied object doesn't affect original object.

Do you need to deep copy integers?

Making a copy of the list is a way to defend against mutation; a deep copy is needed here to make copies of both the outer list and the inner lists (i.e. the rows), which are also mutable. But objects such as integers and strings are immutable, so their state cannot be modified.

What is difference between shallow copy and Deepcopy?

In Shallow copy, a copy of the original object is stored and only the reference address is finally copied. In Deep copy, the copy of the original object and the repetitive copies both are stored.

Is list copyOf a deep copy?

The copyOf method does not make a deep copy, according to the documentation it returns a non-mutable view, i.e. a read-only list. It does not make copies of the elements in the list.


2 Answers

It was suggested in another answer that this may be due to the fact Python has interned objects for small integers. While this statement is correct, it is not what causes that behaviour.

Let's have a look at what happens when we use bigger integers.

> from copy import deepcopy
> x = 1000
> x is deepcopy(x)
True

If we dig down in the copy module we find out that calling deepcopy with an atomic value defers the call to the function _deepcopy_atomic.

def _deepcopy_atomic(x, memo):
    return x

So what is actually happening is that deepcopy will not copy an atomic value, but only return it.

By example this is the case for int, float, str, function and more.

like image 88
Olivier Melançon Avatar answered Oct 19 '22 04:10

Olivier Melançon


The reason of this behavior is that Python optimize small integers so they are not actually in different memory location. Check out the id of 1, they are always the same:

>>> x = 1
>>> y = 1
>>> id(x)
1353557072
>>> id(y)
1353557072

>>> a = [1, 2, 3, 4, 5]
>>> id(a[0])
1353557072

>>> import copy
>>> b = copy.deepcopy(a)
>>> id(b[0])
1353557072

Reference from Integer Objects:

The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object. So it should be possible to change the value of 1. I suspect the behaviour of Python in this case is undefined. :-)

like image 41
Yu Hao Avatar answered Oct 19 '22 04:10

Yu Hao