Skip to content
UniCircle
EasyConceptualObject identity and copying

is vs ==, and shallow copy vs deep copy

Question PY-COP-003

Explain the difference between is and ==. Then explain what b = a, b = a.copy() and b = copy.deepcopy(a) each do when a = [[1, 2], [3, 4]].

Show the explanation

`==` compares values. `is` compares identity.

  • a == b calls a.__eq__(b): do the two objects hold equal values?
  • a is b asks whether both names refer to the same object in memory (id(a) == id(b)).
  • Use is only for singletons: x is None, x is True. Never use it to compare numbers or strings. x is 1000 can be False even when x == 1000. CPython caches small integers (−5 to 256) and some strings, so is sometimes seems to work, but that is an implementation detail. Python 3.8+ warns about is used with a literal.

Three ways to "copy" `a = [[1, 2], [3, 4]]`

CodeNew outer list?New inner lists?After b[0].append(9), is a changed?
b = ano (same object)noyes
b = a.copy() / a[:] / list(a) / copy.copy(a)yes (shallow copy)no; the inner lists are sharedyes
b = copy.deepcopy(a)yesyes, recursivelyno

With a shallow copy, b.append([5]) does not affect a, but changes inside the shared inner lists do.

Deep copy details: deepcopy remembers the objects it has already copied (a memo dict), so it handles shared references and cycles. It is slower, and some objects (open files, locks) cannot be deep-copied. Classes can customise copying with __copy__ and __deepcopy__.

Rule of thumb: for a list of immutable values such as numbers or strings, a shallow copy is enough. For nested mutable structures, such as a matrix or a list of dicts, use deepcopy or rebuild the structure explicitly: [row[:] for row in grid].

Original UniCircle question. Last reviewed 22 Oct 2026.