3

Given that everything in python is by reference, I do understand what's happening in the code below:

a = ['one']*3       // a = ['one', 'one', 'one']
b = [a]*3           // b = [['one', 'one', 'one'], ['one', 'one', 'one'], ['one', 'one', 'one']]
b[1][2] = 'two'  

And now, b is

[['one', 'one', 'two'], ['one', 'one', 'two'], ['one', 'one', 'two']]

Because we made b refer three times the same object referred by a, reassigning any one of the component, change is seen at three places.

But, then why the same thing occurs when

a = [['one']]*3        // a = [['one'], ['one'], ['one']]
a[1] = ['two']        

does not make a = ['two', 'two', 'two'], but just [['one'], ['two'], ['one'] as if a now has three different objects pointed to.

Am I missing some logic here?

Thanks in advance, Nikhil

Nikhil J Joshi
  • 1,177
  • 2
  • 12
  • 25
  • Not a duplicate, but [this question](http://stackoverflow.com/questions/20699736/why-should-i-refer-to-names-and-binding-in-python-instead-of-variables-and/20700226#20700226) relates to yours and might help understand what is going on behind the scenes. – aquavitae Jan 14 '14 at 05:49

3 Answers3

3

You are not changing the contents of a[1], you are rebinding it to point to a separate array. This has no effect on a[0] and a[2].

Try the following instead:

In [4]: a = [['one']]*3

In [5]: a[1][0] = 'two'

In [6]: a
Out[6]: [['two'], ['two'], ['two']]
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • seems an acceptable answer :)... but a bit of confusion: a is a 1d array as much as b was 2d in the previous example. Then why do we need `a[1][0]` to refer to the first element of the object explicitly?... it appears as if `a` and `a[1]` are two different references here :( – Nikhil J Joshi Jan 12 '14 at 16:09
  • @NikhilJJoshi: I am not sure I follow your last remark. `a`, `a[1]` and `a[1][0]` are indeed three different references. – NPE Jan 12 '14 at 16:13
  • I was trying to understand where exactly `a` and `b` differ. It was evident that `b[0][1], b[1][1]', and `b[2][1]` referred to the same object, then why not in `a[0]`, `a[1]`, and `a[2]`.... perhaps I am to understand a bit more deeply. – Nikhil J Joshi Jan 12 '14 at 16:20
1

Probably the best way I have found to understand how references work is to run them through the simulator at Python Tutor (clicking that link will run the example you had above). This makes the situation very clear. It's also worth reading this article.

chthonicdaemon
  • 19,180
  • 2
  • 52
  • 66
1

A key thing to remember is that objects have existence and an identity independent of names which point to them; and x = y does not mean "change the value of the object pointed to by x to what y is pointing to". It means "make x point to what y is pointing to".

Using id might help to clarify what is going on:

>>> a = [['one']]*3
>>> (id(a[0]), id(a[1]), id(a[2]))
(140193404836320, 140193404836320, 140193404836320)
>>> a[1] = ['two']
>>> (id(a[0]), id(a[1]), id(a[2]))
(140193404836320, 140193368088088, 140193404836320)

Initially, a[0], a[1], and a[2] are all the same object, as one would expect:

       +------+------+------+
  a -->|      |      |      |
       +------+------+------+
            \    |     /
             |   |     |
             v   v     v
             +---------+
             | ['one'] |
             +---------+

Then a[1] = ['two'] makes a[1] point to a new object:

       +------+------+------+
  a -->|      |      |      |
       +------+------+------+
         |       |      |
         |       |      |
         |       |      |
         |       v      |
         |  +---------+ |
         |  | ['two'] | |
         |  +---------+ |
         |              |
         |  +---------+ | 
         \> | ['one'] |</
            +---------+   

Note that the diagram is simplified to show the essentials, ['one'] and ['two'] aren't simple values as they appear in the diagram.

Prateek
  • 2,377
  • 17
  • 29