It makes no sense to have a type produce mutable or immutable instances. Their behaviour would radically change; half the methods would no longer work, and it makes it much harder to apply optimisations.
You are free to create your own types that allow mutation in some cases, are immutable in others, but the built-in types make use of specific optimisations and core Python functionality counts on objects being truly immutable, not based on programmer preference.
The programmer is free to switch between types; bytes
vs. bytearray
, tuple
vs. list
, frozenset
vs. set
, where it makes sense.
The Python FAQ addresses why strings are immutable:
Why are Python strings immutable?
There are several advantages.
One is performance: knowing that a string is immutable means we can allocate space for it at creation time, and the storage requirements are fixed and unchanging. This is also one of the reasons for the distinction between tuples and lists.
Another advantage is that strings in Python are considered as “elemental” as numbers. No amount of activity will change the value 8 to anything else, and in Python, no amount of activity will change the string “eight” to anything else.
Add to this that dictionaries and sets use hash tables, an algorithm that requires that keys are immutable for locating keys by their value alone.
From the same FAQ again:
Why must dictionary keys be immutable?
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.