0

After line 7, I haven't written a single line of code which mentions the list named 'outer'. However, if you execute it, you'll see that the 'outer' (i.e, the nested lists inside it) list would change/update due to lines 10 and 12...

I'm guessing it has something to do with reference vs value. My question is, why didn't line 13 effect (change/update) the 'outer' list the same way that lines 7 and 10 did? I'm trying to undertand this concept. How do I go about it. I know there's a lot of resources online.. but I don't even know what to google. Please help.

inner = []
outer = []

lis = ['a', 'b', 'c']

inner.append(lis[0])
outer.append(inner) <<---- Line 7 <<

print(outer)
inner.append(lis[1]) <<---- Line 10 <<
print(outer)
inner.append(lis[2]) <<---- Line 12 <<
print(outer)
lis[2] = 'x' <<---- Line *******13******* <<
print(outer)
James
  • 32,991
  • 4
  • 47
  • 70
  • Append is to add a new element into your empty list, that's why your `outer` was updated. On the other hand, your line 13 is to update the list `lis`, not the `outer`, so that's why your `outer` list was not affected at all. –  Mar 06 '22 at 13:54
  • Does this answer your question? [Are Python variables pointers? Or else, what are they?](https://stackoverflow.com/questions/13530998/are-python-variables-pointers-or-else-what-are-they) – MisterMiyagi Mar 06 '22 at 14:12

2 Answers2

0

This is a boiled-down version of your example:

some_list = []
a = 2

some_list.append(a)
a = 3

print(some_list)  # output: [2]
print(a)  # output: 3

If we follow your original logic, you would expect some_list to contain the value 3 when we print it. But the reality is that we never appended a itself to the list. Instead, writing some_list.append(a) means appending the value referenced by a to the list some_list.

Remember, variables are simply references to a value. Here's the same snippet as above, but with an explanation of what's referencing what.

some_list = []  # the name "some_list" REFERENCES an empty list
a = 2  # the name "a" REFERENCES the integer value 2

some_list.append(a)  # we append the value REFERENCED BY "a" 
                     # (the integer 2) to the list REFERENCED 
                     # BY "some_list". That list is not empty
                     # anymore, holding the value [2]

a = 3  # the name "a" now REFERENCES the integer value 3. This
       # has no implications on the list REFERENCED BY "some_list".
       # We simply move the "arrow" that pointed the name "a" to
       # the value 2 to its new value of 3

print(some_list)  # output: [2]
print(a)  # output: 3

The key aspect to understand here is that variables are simply references to a value. Writing some_list.append(a) does not mean "place the variable a into the list" but rather "place the value that the variable a references at this moment in time into the list". Variables cannot keep track of other variables, only the values that they are a reference to.

This becomes even clearer if we append to some_list a second time, after modifying the value that a references:

some_list = []
a = 2

some_list.append(a)
a = 3
some_list.append(a)

print(some_list)  # output: [2, 3]
print(a)  # output: 3
jfaccioni
  • 7,099
  • 1
  • 9
  • 25
-1

In Python, when you store a list in variable you don't store the list itself, but a reference to a list somewhere in the computer's RAM. If you say

a = [0, 1, 2]
b = a
c = 3

then both a and b will be references to the same list as you set b to a, which is a reference to a list. Then, modifying a will modify b and vice-versa. c, however, is an integer; it works differently. It's like that:

  ┌───┐
a │ █━┿━━━━━━━━━━━━━━━┓ ┌───┬───┬───┐
  └───┘               ┠→│ 0 │ 1 │ 2 │
  ┌───┐               ┃ └───┴───┴───┘
b │ █━┿━━━━━━━━━━━━━━━┛
  └───┘
  ┌───┐
c │ 3 │
  └───┘

a and b are references to a same list, but c is an pointer to an integer which is copied (the integer) when you say d = c. The reference to it, however, is not copied.

So, let's go back to your program. When you say inner.append(lis[n]) you add the value at the end of the list inner. You don't add the reference to the item #2 of the list lis but you create a copy of the value itself and add to the list the reference to this copy! If you modify lis, then it will have an impact only on variables that are references to lis.

If you want inner to be modified if you modify lis, then replace the inner.append(lis[n])s by inner.append(lis).

  • "``c`` is an integer and is the value itself and not a reference to it" That's not true, and it's a common misconception. The reference implementation uses C pointers that refer to objects; even if other implementations use a different scheme (e.g. PyPy's tagged pointers) they still have all the *semantics* of referencing. ``c`` also refers to its target, there is just no way to *modify* its target. – MisterMiyagi Mar 06 '22 at 14:35
  • Thanks @MisterMiyagi, I corrected my answer. – Desktop Firework Mar 07 '22 at 12:03
  • ``a``, ``b`` and ``c`` all are the same kind. If ``c`` is a pointer, so are ``a`` and ``b``. – MisterMiyagi Mar 07 '22 at 12:03
  • Yes, but `a` and `b` are pointers to a list where `c` is a pointer to an integer. Pointers to lists work differently than pointers to integers. – Desktop Firework Mar 07 '22 at 12:08
  • "Pointers to lists work differently than pointers to integers." No they don't! They're all ``PyObject*`` pointers. The things they *point to* work differently from each other, but the pointers themselves are exactly the same. – MisterMiyagi Mar 07 '22 at 12:11
  • Yes, you're right... But then, why will `a` be modified if I do `b = a` and then `b[0] += 1` if both `a` and `b` are lists, and why will `a` not be modified if they are integers? (well, pointers to) – Desktop Firework Mar 07 '22 at 12:14
  • 1
    Because an integer is *immutable*. It cannot be modified. In your example, the thing *pointed to* has its value changed, not the thing *pointing*. ``b[0] += 1`` modifies the first element of the list pointed to by ``b``; it does not modify the name ``b``. – MisterMiyagi Mar 07 '22 at 12:17
  • Oh, thanks. I understand now. – Desktop Firework Mar 07 '22 at 12:18