If two variables point to the same object, why doesn’t reassigning one variable affect the other?

Python has names which refer to objects. Objects exist separately from names, and names exist separately from the objects they refer to.

# name a
a = 1337
    # object 1337

When assigning “a name to a name”, the right-hand side is evaluated to the referred to object. Similar to how 2 + 2 evaluates to 4, a evaluates to the original 1337.

# name b
b = a
    # object referred to by a -> 1337

At this point, we have a -> 1337 and b -> 1337 – note that neither name knows the other! If we test a is b, both names are evaluated to the same object which is obviously equal.

Reassigning a name only changes what that name refers to – there is no connection by which other names could be changed as well.

# name a - reassign
a = 9001
  # object 9001

At this point, we have a -> 9001 and b -> 1337. If we now test a is b, both names are evaluated to different objects which are not the same.


If you come from languages such as C, then you are used to variables containing values. For example, char a = 12 can be read as “a is a memory region containing 12“. On top, you can have several variables use the same memory. Assigning another value to a variable changes the content of the shared memory – and therefore the value of both variables.

+- char a -+
|       12 |
+--char b -+

# a = -128

+- char a -+
|     -128 |
+--char b -+

This is not how Python works: names do not contain anything, but refer to separate values. For example, a = 12 can be read as “a is a name which refers to the value 12“. On top, you can have several names refer to the same value – but it will still be separate names, each with its own reference. Assigning another value to a name changes the reference of that name – but leaves the reference of the other name untouched.

+- name a -+ -\
               \
                --> +- <12> ---+
               /    |       12 |
+- name b -+ -/     +----------+

# a = -128
                    +- <-128> -+
+- name a -+ -----> |     -128 |
                    +----------+

                    +- <12> ---+
+- name b -+ -----> |       12 |
                    +----------+

A point of confusion is that mutable objects can appear to violate the separation of names and objects. Commonly, these are containers (e.g list, dict, …) and classes exhibit the same behaviour by default.

# name m
m = [1337]
    # object [1337]
# name n
n = m
    # object referred to by m

Similar to a plain integer 1337, a list containing an integer [1337] is an object that can be referred to by several, independent names. As above, n is m evaluates to True and m = [9001] does not change n.

However, certain operations on a name change the value seen by the name and all aliases.

# inplace add to m
m += [9001]

After this operation, m == [1337, 9001] and n is m still holds true. In fact, the value seen by n has also changed to [1337, 9001]. This appears to violate above behaviour, in which aliases did not influence each other.

This is because m += [9001] did not change what m refers to. It only change the content of the list that m (and the alias n) referred to. Both m and n still refer to the original list object, whose value was changed.

+- name m -+ -\
               \                  
                --> +- […] -+     +--- <@0> -+
               /    |    @0 |  -> |     1337 |
+- name n -+ -/     +-------+     +----------+

# m += [9001]

+- name m -+ -\
               \                  
                --> +- […] -+     +--- <@0> -++--- <@1> -+
               /    | @0 @1 |  -> |     1337 ||     9001 |
+- name n -+ -/     +-------+     +----------++----------+

Leave a Comment