Mutable vs. Immutable

Let’s look at two more examples:

>>> str1 = "hello"
>>> str2 = str1
>>> str2 += " world"

What values are str1 and str2 assigned to?

>>> str1
'hello'
>>> str2
'hello world'

That’s not too surprising. Let’s do the same with lists:

>>> list1 = ["hello"]
>>> list2 = list1
>>> list2 += [" world"]
>>> list1
['hello', ' world']
>>> list2
['hello', ' world']

Wait. What happened??

After initializing the strings and lists the situation is:

digraph first {
  rankdir=LR;
  hello [label = "hello", style=dotted, shape=polygon];
  "str1" -> hello [weight=100];
  "str2" -> hello;
}

digraph first {
  rankdir=LR;
  hello [label = "[\"hello\"]", style=dotted, shape=polygon];
  "list1" -> hello [weight=100];
  "list2" -> hello;
}

Where’s the difference then??

1) Strings are immutable objects.

Executing

>>> str2 += " world"
digraph first {
  rankdir=LR;
  hello [label = "hello", style=dotted, shape=polygon];
  helloworld [label = "hello world", style=dotted, shape=polygon];
  "str2" -> helloworld;
  "str1" -> hello;
}

creates a new string!

2) Lists are mutable objects. This means that a list can be modified:

>>> list2 += [" world"]

does not create a new list! The list is modified in place. Therefore both the names list1 and list2 still have the same value.

digraph first {
  rankdir=LR;
  hello [label = "[\"hello\", \" world\"]", style=dotted, shape=polygon];
  "list1" -> hello [weight=100];
  "list2" -> hello;
}

However:

>>> list1 = ["hello"]
>>> list2 = list1
>>> list2 = list2 + [" world"]
>>> list1
['hello']
>>> list2
['hello', ' world']

does create a new list.

digraph first {
  rankdir=LR;
  hello [label = "[\"hello\"]", style=dotted, shape=polygon];
  helloworld [label = "[\"hello\", \" world\"]", style=dotted, shape=polygon];
  "list1" -> hello [weight=100];
  "list2" -> helloworld;
}

There’s something shady going on…

Immutable types

  • Cannot change their value

  • ints, floats, strings, tuples

Mutable types

  • Can change their value

  • All names that have the same value see the change! (Same value does not mean equal value!!)

  • Behavior when performing operations depends on the object’s implementation! E.g. in the earlier example

>>> list2 += [" world"]

is actually

>>> list2.__iadd__(["world"])  

. So the behavior depends on the implementation of __iadd__. However

>>> list2 = list2 + [" world"]

is actually

>>> list2.__add__(["world"])  

. So the behavior depends on the implementation of __add__.