41

I understand the differences between mutable and immutable objects in Python. I have read many posts discussing the differences. However, I have not read anything regarding WHY integers are immutable objects.

Does there exist a reason for this? Or is the answer "that's just how it is"?

Edit: I am getting prompted to 'differentiate' this question from other questions as it seems to be a previously asked question. However, I believe what I'm asking is more of a philosophical Python question rather than a technical Python question.

It appears that 'primitive' objects in Python (i.e. strings, booleans, numbers, etc.) are immutable. I've also noticed that derived data types that are made up of primitives (i.e. dicts, lists, classes) are mutable.

Is that where the line is drawn whether or not an object is mutable? Primitive vs derived?

Ankur Agarwal
  • 23,692
  • 41
  • 137
  • 208
Izzo
  • 4,461
  • 13
  • 45
  • 82
  • 13
    What exactly about an integer would you want to mutate? The bits? – OneCricketeer May 31 '16 at 02:01
  • 2
    Assuming immutability of some types enables all sorts of optimizations. Those optimizations are _most_ pronounced for `str`, but they come into play for `int`, `float`, `tuple`, `frozenset` too... Some would probably argue that immutability makes the code easier to read in lots of situations too. Couple that with the fact that there isn't a natural way to mutate integers (other than `+=`, `*=`, ... which are fairly rare...) and there doesn't seem to be a good reason to not have immutable ints. – mgilson May 31 '16 at 02:25
  • 1
    If you can modify the value `1` to be `2` and the value `2` to be `1` then `2 + 2 == 1` would be `true`; is that really what you want? – Elliott Frisch May 31 '16 at 02:29
  • You may find [abarnert's answer](http://stackoverflow.com/a/29604031/4014959) (to the question linked above by StanleyR) helpful. – PM 2Ring May 31 '16 at 14:08

2 Answers2

29

Making integers mutable would be very counter-intuitive to the way we are used to working with them.

Consider this code fragment:

a = 1       # assign 1 to a
b = a+2     # assign 3 to b, leave a at 1

After these assignments are executed we expect a to have the value 1 and b to have the value 3. The addition operation is creating a new integer value from the integer stored in a and an instance of the integer 2. If the addition operation just took the integer at a and just mutated it then both a and b would have the value 3.

So we expect arithmetic operations to create new values for their results - not to mutate their input parameters.

However, there are cases where mutating a data structure is more convenient and more efficient. Let's suppose for the moment that list.append(x) did not modify list but returned a new copy of list with x appended. Then a function like this:

def foo():
  nums = []
  for x in range(0,10):
    nums.append(x)
  return nums

would just return the empty list. (Remember - here nums.append(x) doesn't alter nums - it returns a new list with x appended. But this new list isn't saved anywhere.)

We would have to write the foo routine like this:

def foo():
  nums = []
  for x in range(0,10):
    nums = nums.append(x)
  return nums

(This, in fact, is very similar to the situation with Python strings up until about 2.6 or perhaps 2.5.)

Moreover, every time we assign nums = nums.append(x) we would be copying a list that is increasing in size resulting in quadratic behavior. For those reasons we make lists mutable objects.

A consequence to making lists mutable is that after these statements:

a = [1,2,3]
b = a
a.append(4)

the list b has changed to [1,2,3,4]. This is something that we live with even though it still trips us up now and then.

TemporalWolf
  • 7,727
  • 1
  • 30
  • 50
ErikR
  • 51,541
  • 9
  • 73
  • 124
  • 14
    I don't think that the statement `"Making integers mutable would be very counter-intuituve to the way we are used to working with them."` is necessarily true. There are lots of other languages which have mutable integers (`C` is a very common example...). Just because we're used to python integers being immutable *now* doesn't mean that we were used to immutable integers when the original decision was made. – mgilson May 31 '16 at 02:43
  • 25
    The fact that `a += 2` creates a new integer is counter-intuitive to me. Most of the time though, it really doesn't make a difference. One key post that comes to mind is [this one](https://stackoverflow.com/questions/306313/is-operator-behaves-unexpectedly-with-integers), which is just one more oddity about the fact that "new" integers are not always created – Frank Bryce May 31 '16 at 02:48
  • @mgilson - Would you consider `int` values mutable in C? Certainly `gmp` bigint objects are mutable, but I don't see C `ints` being mutable in the same way. Ultimately I think we would find making Python integers mutable would cause more problems than it would solve. What we really want to do is to make our compilers / run-times smarter so that they can detect when they use mutation instead of creating a new object. That will give us the efficiency of mutable values with the safety of immutable values. – ErikR May 31 '16 at 02:55
  • 2
    @ErikR consider in C: `int* a; int *b; *a = 5; b = a; *a = 10;`. Now the value of `*b` has changed also. – Frank Bryce May 31 '16 at 02:57
  • For instance, in the case of `b = a + 2`, what we want to happen at run-time is that a "2" integer gets created and then incremented (mutated) by _a_ and then stored in _b_. – ErikR May 31 '16 at 02:58
  • 4
    @ErikR the difference is that integers in C are value types, and python has only reference types. The closest analogy will be `int*` versus an integer in python. In C, an integer at a location in memory can change, so in C the integer is mutable. In python, an integer is a reference, but python does not allow you to change the value of the integer at the other end of that reference. C does. – Frank Bryce May 31 '16 at 03:00
  • 1
    Another language that has mutable integers is `Fortran` (though admittedly not as popular as C...). IIRC, `Go` also has mutable ints... Basically, it's not all that uncommon of a paradigm... – mgilson May 31 '16 at 03:15
  • 7
    @ErikR a = 1 b = a+2 . This statement will not change value of a. You are saying if numbers are mutable then a will change. It will not. a = 1 b=a b= 10 this statement will change the value of a if number are mutable. beacuse a and b are pointing to same object and we are changing the value of object so it will reflect to both the objects – Prithvipal Singh Mar 31 '17 at 12:07
  • @mgilson integers in C and Fortran are straight values. Python doesn't have straight values and references to immutable types are closer in behaviour to straight values than references to mutable types are. – plugwash May 10 '18 at 20:44
  • 1
    I can follow your line of reasoning somehow, but this point is moot "If the addition operation just took the integer at a and just mutated it then both a and b would have the value 3." I dont know any langauge where `b = a + 3` mutates `a`, actually that would be very counter-intuitive. – 463035818_is_not_an_ai Apr 29 '20 at 13:25
19

What are the design decisions to make numbers immutable in Python?

There are several reasons for immutability, let's see first what are the reasons for immutability?

1- Memory

  • Saves memory. If it's well known that an object is immutable, it can be easily copied creating a new reference to the same object.
  • Performance. Python can allocate space for an immutable object at creation time, and the storage requirements are fixed and unchanging.

2- Fast execution.

  • It doesn't have to copy each part of the object, only a simple reference.
  • Easy to be compared, comparing equality by reference is faster than comparing values.

3- Security:

  • In Multi-threading apps Different threads can interact with data contained inside the immutable objects, without to worry about data consistency.
  • The internal state of your program will be consistent even if you have exceptions.
  • Classes should be immutable unless there's a very good reason to make them mutable....If a class cannot be made immutable, limit its mutability as much as possible

4- Ease to use

  • Is easier to read, easier to maintain and less likely to fail in odd and unpredictable ways.
  • Immutable objects are easier to test, due not only to their easy mockability, but also the code patterns they tend to enforce.

5- Keys must be immutable. Which means you can use strings, numbers or tuples as dictionary key. This is something that you want to use.

The hash table implementation of dictionaries uses a hash value calculated from the key value to find the key. If the key were a mutable object, its value could change, and thus its hash could also change. But since whoever changes the key object can’t tell that it was being used as a dictionary key, it can’t move the entry around in the dictionary. Then, when you try to look up the same object in the dictionary it won’t be found because its hash value is different. If you tried to look up the old value it wouldn’t be found either, because the value of the object found in that hash bin would be different.

Going back to the integers:

  • Security (3), Easy to use (4) and capacity of using numbers as keys in dictionaries (5) are reasons for taken the decision of making numbers immutable.

  • Has fixed memory requirements since creation time (1).

  • All in Python is an object, the numbers (like strings) are "elemental" objects. No amount of activity will change the value 8 to anything else, and no amount of activity will change the string “eight” to anything else. This is because a decision in the design too.

Facundo Victor
  • 3,308
  • 1
  • 25
  • 20