3

I'm total beginner to Python, so please could you explain me why the following situation happens. Consider the following code:

>>> A = [1, 2, 3, 4]
>>> B = A[0:2]
>>> print id(A) == id(B)
False
>>> print id(A[0]) == id(B[0])
True                              #Why?
>>> A[0] = 9
>>> A
[9, 2, 3, 4]
>>> B 
[1, 2]
>>> print id(A[0]) == id(B[0])
False                             #Contradiction?

As you can see from the code above, I slice the list A and copy it to B, but, why print id(A[0]) == id(B[0]) evalutes Trueon the first one but the opposite when I change either of A or B's value?

Burak.
  • 598
  • 7
  • 19
  • 1
    [CPython caches small integers](http://stackoverflow.com/questions/306313/is-operator-behaves-unexpectedly-with-integers) so any value from -5 to 256 will have same id anytime you check it. – Łukasz Rogalski Oct 21 '16 at 13:56
  • http://stackoverflow.com/questions/28329498/why-does-a-space-affect-the-identity-comparison-of-equal-strings/28329522#28329522 – Padraic Cunningham Oct 21 '16 at 14:04

3 Answers3

2

When you do B = A[0:2], that ends up essentially doing this, as part of it: B[0] = A[0]. So the object (the integer 1) in A[0] is the same object which is in B[0].

When you set A[0] = 9, then those objects are no long the same.

Also, as @ŁukaszRogalski pointed out CPython caches small integers. So we've got A[0] == 1 == B[0], and id(1) == id(1).

When A[0] == 9, then 9 != 1 == B[0], and id(9) != id(1).

B. Eckles
  • 1,626
  • 2
  • 15
  • 27
  • oh so it has nothing to do with the memory location? – Burak. Oct 21 '16 at 13:51
  • https://docs.python.org/2/library/functions.html#id If it's CPython, it would be the memory location. But if it's not, it's just guaranteed to be unique for a unique object. – B. Eckles Oct 21 '16 at 13:53
  • Also, my answer is slightly off. Hang on while I adjust it. – B. Eckles Oct 21 '16 at 13:54
  • @Burak. I would take a look at [this](http://stackoverflow.com/q/15667189/3220135) question and the answers to it.. they describe it pretty well – Aaron Oct 21 '16 at 13:54
2

Try this:

id(1) == id(1) #True

The reason is that these number constants will be reused throughout the program. So its like some memory is given to store 1 and then wherever 1 is mentioned in the program, the same memory will be used so only a reference to that memory will be created. Object remains the same.

Shasha99
  • 1,746
  • 2
  • 16
  • 30
  • Oh, ok I initially thought it always fetches memory location rather than the actual value. :) – Burak. Oct 21 '16 at 13:53
  • Be assured that in your case, A and B are referring to different things. – Shasha99 Oct 21 '16 at 13:55
  • @Burak it does, but python will only store one object for each literal integer. – Aaron Oct 21 '16 at 13:55
  • The problem comes when your list contains references instead of constants. In that case the changes made from 1 place will reflect automatically to another place. We do deep copy in that case. – Shasha99 Oct 21 '16 at 13:58
1

Basically, python doesn't create new objects from every item within a list, whenever you copy/slice a it.

But, Although this won't cause any trouble with immutable objects, you should be careful with mutable objects:

In [22]: A = [[1, 2], 2, 3, 4]

In [23]: B = A[0:2]

In [24]: id(A[0]) == id(B[0])
Out[24]: True

In [27]: A[0][1] = 99

In [28]: B
Out[28]: [[1, 99], 2]

In this case you can use copy.deepcopy to create a new object of the slice:

In [32]: import copy

In [33]: B = copy.deepcopy(A[0:2])

In [34]: A[0][1] = 5

In [35]: B
Out[35]: [[1, 99], 2]

In [36]: id(A[0]) == id(B[0])
Out[36]: False
           ^
        New Object
Mazdak
  • 105,000
  • 18
  • 159
  • 188