← CS Lab Programming Foundations / Python Mutability & References Open standalone ↗

In Python a variable is a name, not a box. Assignment doesn't copy a value into a slot — it ties a name to an object that lives somewhere in memory. Two names can point at the same object, and whether changing one is visible through the other depends on two things: is the object mutable, and do you change it in place or rebind the name to something new?

Where you meet it

What it does

Every object has three fixed things: an identity (its address, never changes), a type, and a value. For mutable objects (lists, dicts, sets) the value can change in place; for immutable ones (int, str, tuple) it can't. Names just refer to these objects — assignment moves the name, it never copies the object.

b = a never copies — it sticks a second label on the same object. Whether that bites you depends on one thing: can the object be mutated?

How it works

Think of a name as a label stuck on an object. b = a sticks a second label on the same object — that's an alias, and a is b is True. Mutating through one label is visible through every label. Rebinding a name (=) just peels its label off and moves it to a different object; the others stay put.

a = [1, 2, 3]
b = a            # b is an alias — same object
a.append(99)     # mutate in place
print(b)         # [1, 2, 3, 99]  ← b sees it too!

x = 5
y = x            # both name the int 5
x = x + 1        # int is immutable → builds a NEW object
print(y)         # 5              ← y still names the old 5

The list is mutated, so both names see the change. The int can't be mutated, so x + 1 creates a fresh object and rebinds x only — y is untouched. To get an independent list, copy it: b = a.copy() or b = a[:].

Watch out

  • Mutable default arguments. def f(items=[]) creates the list once, when the function is defined, and shares it across every call. Use items=None and build a fresh list inside.
  • is is not ==. is compares identity (same object); == compares value. Use is only for singletons like None; use == for everything else.
  • A shallow copy isn't deep. list.copy(), [:] and copy.copy() duplicate the outer object but keep references to nested objects. For full independence use copy.deepcopy().

Go deeper

In Python ist eine Variable ein Name, keine Kiste. Eine Zuweisung kopiert keinen Wert in ein Fach — sie bindet einen Namen an ein Objekt, das irgendwo im Speicher liegt. Zwei Namen können auf dasselbe Objekt zeigen, und ob eine Änderung am einen durch den anderen sichtbar ist, hängt an zwei Fragen: Ist das Objekt veränderlich (mutable), und änderst du es an Ort und Stelle oder bindest du den Namen an etwas Neues?

Wo es vorkommt

Was es tut

Jedes Objekt hat drei feste Dinge: eine Identität (seine Adresse, ändert sich nie), einen Typ und einen Wert. Bei veränderlichen Objekten (Listen, Dicts, Sets) kann der Wert in-place geändert werden; bei unveränderlichen (int, str, tuple) nicht. Namen verweisen nur auf diese Objekte — eine Zuweisung verschiebt den Namen, sie kopiert nie das Objekt.

b = a kopiert nie — es klebt ein zweites Etikett aufs selbe Objekt. Ob dich das beißt, hängt an einem: Lässt sich das Objekt mutieren?

Wie es funktioniert

Stell dir einen Namen als Etikett auf einem Objekt vor. b = a klebt ein zweites Etikett auf dasselbe Objekt — das ist ein Alias, und a is b ergibt True. Eine In-place-Änderung über ein Etikett ist über alle Etiketten sichtbar. Einen Namen neu zuzuweisen (=) löst nur sein Etikett ab und klebt es auf ein anderes Objekt; die übrigen bleiben, wo sie sind.

a = [1, 2, 3]
b = a            # b ist ein Alias — dasselbe Objekt
a.append(99)     # in-place mutieren
print(b)         # [1, 2, 3, 99]  ← b sieht es auch!

x = 5
y = x            # beide benennen die int 5
x = x + 1        # int ist unveränderlich → baut ein NEUES Objekt
print(y)         # 5              ← y benennt weiter die alte 5

Die Liste wird mutiert, also sehen beide Namen die Änderung. Die int lässt sich nicht mutieren, also erzeugt x + 1 ein frisches Objekt und bindet nur x neu — y bleibt unberührt. Für eine unabhängige Liste kopieren: b = a.copy() oder b = a[:].

Worauf achten

  • Veränderliche Default-Argumente. def f(items=[]) erzeugt die Liste einmal, bei der Definition der Funktion, und teilt sie über alle Aufrufe. Stattdessen items=None nehmen und drinnen eine frische Liste bauen.
  • is ist nicht ==. is vergleicht die Identität (dasselbe Objekt), == den Wert. is nur für Singletons wie None verwenden, == für alles andere.
  • Eine flache Kopie ist nicht tief. list.copy(), [:] und copy.copy() duplizieren das äußere Objekt, behalten aber Referenzen auf verschachtelte Objekte. Für volle Unabhängigkeit copy.deepcopy() nutzen.

Mehr dazu

Next up
Data Science & Statisticspandas .loc vs .iloc Data Science & Statisticspandas Boolean Filtering All concepts →