Why are Python strings immutable?

Because a string's value can never change, its hash can never go stale and a reference to it can never be invalidated by someone else. That is what makes strings usable as dictionary keys and safe to share without copying. The cost is that every "modification" builds a new object.

Overview

What immutability actually means

There is no operation in Python that changes a string in place. s.upper(), s.replace(), s.strip() and s + t all return a new string and leave the original exactly as it was. Assigning to an index — s[0] = 'A' — is not slow, it is a TypeError.

This is enforced, not advisory. There is no private method and no escape hatch, which is what lets the interpreter make assumptions it could not otherwise make.

StringsConceptualEasy

Step through it

What to watch

  • t = s makes no copy — both names point at one object.
  • upper() returns a different object; s is untouched.
  • The stable hash at the end is the payoff, not a side effect.

Say this out loud

"Immutable means every operation returns a new string. It buys hashability - so strings can be dict keys - and it means sharing a string is free. It costs you concatenation in a loop, which is why you use join."

Why are Python strings immutable?

Why are Python strings immutable, and what does that buy you?

The three things it buys

Hashability. A dictionary stores a key in a slot chosen from its hash. If the key could change after insertion, its hash would no longer match its slot and the entry would become unreachable. Immutable types can be keys; mutable ones cannot, which is why {[1,2]: 'x'} raises and {(1,2): 'x'} does not.

Free sharing. Passing a string to a function, storing it in two places, closing over it — none of these need a defensive copy, because no one can modify it behind your back. In a language with mutable strings, library code often copies on the way in just in case.

Interning. CPython reuses one object for short string literals that look like identifiers, so equality can often be settled by an identity check. That is an optimisation immutability makes legal.

What it costs, and the one place it bites

Every edit allocates. Usually that is irrelevant — one replace on one line costs nothing you can measure. It matters in exactly one shape: building a string a piece at a time in a loop.

Each += copies everything accumulated so far, so n appends copy 1 + 2 + 3 + ... + n characters, which is O(n²). The fix is "".join(parts): one pass to total the lengths, one allocation, one copy. The editor below measures both.

The follow-up you should expect

"If strings are immutable, why does s += 'x' sometimes look fast?" CPython has a special case that resizes a string in place when the target is a plain local variable and nothing else refers to it. It is real, it is invisible, and it stops firing the moment you store into an attribute or a list. Do not build on it.

Run it in Python

Object identities before and after a "modification", then the cost of ignoring what that implies — measured at three sizes so the shape of the curve is visible rather than asserted.

immutable.pyPython 3
Output

How the code works

  1. t = sBinds a second name to the same object, which t is s confirms. No copy is made because none is needed — neither name can change the value.
  2. u = s.upper()A different id. Every string method returns a new object; none of them has a way to modify the receiver.
  3. hash("cat") == hash(s)The hash is a function of the value, and the value is frozen for the object's whole life. That is the precondition a dictionary key has to meet.
  4. self.text += "x"Accumulating into an attribute rather than a local is deliberate: CPython can resize a local string in place, which would hide the quadratic the table is there to show.

Change one thing

  • Add v = "cat" and check v is s. Short literals are interned, so it is often True — and relying on that is still a bug.
  • Swap b.text for a local variable and re-run. Whether the quadratic disappears depends on your interpreter, which is itself the argument for join.

Where this runs

Real CPython, compiled to WebAssembly and running on your own machine — nothing is uploaded. The first run takes a few seconds while the interpreter downloads; after that it is immediate. Need more room, or want to paste your own attempt? Use the Python compiler.

Check yourself

0 of 3

Answer without scrolling back up.

  1. Why can a string be a dictionary key when a list cannot?

  2. What does s.upper() do to s?

  3. Building a string with += in a loop is O(n²) because each step:

Cheat sheet

Why are Python strings immutable?

Because a string's value can never change, its hash can never go stale and a reference to it can never be invalidated by someone else. That is what makes strings usable as dictionary keys and safe to share without copying. The cost is that every "modification" builds a new object.

INTERVIEW · vizlearn.in/interview/why-are-python-strings-immutable.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.