1

I have the following code that works as expected:

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

>>> b is a
True

if I change it up a little it still works:

a = [1, 2, 3, 4]
b = a[2] * 2

>>> b is a[2] * 2
True

Now the problem:

a = [1, 2, 3, 4]
b = a * 2

>>> b is a * 2
False    

Can someone please explain to me why this returns False, while b is a[2] * 2 returns True?

Timmay
  • 85
  • 4
  • 13

3 Answers3

4

When a is a list, a * 2 creates a new list instance. If you call a * 2 twice, you create two new list instances -- that's why b is a * 2 yields False.

The reason that you get True for b is a[2] * 2 is an optimisation of CPython that caches small integers. Since integers are immutable in Python, it actually does not matter if you get a new instance or a cached one, and for small integers, Python returns a cached version if you hit the same integer again. Also try

>>> a = [1, 2, 300, 4]
>>> b = a[2] * 2
>>> b is a[2] * 2
False
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 3
    The bottom line of course, is don't use `is` unless you really want [object identity](http://docs.python.org/library/stdtypes.html#comparisons) ; use `==` for numerical comparison. – Andrew Mar 10 '11 at 20:48
  • Great explanation! @Andrew, I definitely see the benefit of using `==` instead of `is`. – Timmay Mar 10 '11 at 20:56
2

Identical lists aren't equivalent when compared is unless they reference the same list. Just because the lists have the same values doesn't mean they reference the same list in memory.

E.g.,

>>> a = [1,2,3]
>>> id(a) # memory location list a references
161267628
>>> b = [1,2,3]
>>> id(b) # memory location list b references, a different memory location than list a
161276396
>>> a == b 
True
>>> a is b
False
>>> c = a # by this method of assignment; c points to the same point that a does;
# hence changes to a and changes to c, will change both.
>>> id(c) # memory location that c references; this is the same as where a points.
161267628
>>> a is c
True
>>> c.append(4)
>>> print a
[1, 2, 3, 4]
>>> print b
[1, 2, 3]
>>> print c
[1, 2, 3, 4]
>>> d = a[:] # this just copies the values in a to d.  
>>> id(d)
161277036

This makes sense that they point to different memory locations, because if you may want to say change the first list (like append 4 to the end a) without modifying b which wouldn't be possible if a and b pointed to the same location in memory.

dr jimbob
  • 17,259
  • 7
  • 59
  • 81
  • I like your use of memory locations, as it has helped me to understand what python is actually doing with the assignments. I have a feeling I will use `id()` a lot in the future. – Timmay Mar 10 '11 at 21:07
0

a * 2 constructs a new list, while an integer has identity with itself.

>>> type(a[2] * 2)
<type 'int'>
>>> type(a * 2)
<type 'list'>
Bittrance
  • 2,202
  • 2
  • 20
  • 29