Skip to content
Free public beta until December 4, 2026: every course is open, no card needed. After that, the first chapter of each course stays free and full access is a one-time $39 ($19 for up to 100 founding members chosen for helpful feedback). Your progress is kept. How the beta works

Copying versus aliasing

Two names for one object, a shallow copy, a deep copy, or a NumPy view. Whether a change in one place shows up in another depends on which you have.

Every Python name points at an object. The question is always is this a second name for the same object, or a different object?

  • b = a never copies. Both names point at one object, so if it's mutable (a list, dict or set), a change through b shows up in a.
  • Passing a list to a function is the same: the function gets another name for your list, not a copy.
  • You want an independent outer list → a shallow copy: a.copy(), list(a) or a[:]. Nested lists inside are still shared.
  • You want nothing shared at any depth → copy.deepcopy(a).
  • You're checking "same object?" rather than "same value?" → use is, not ==.
  • NumPy slices are views of the same memory; call .copy() when you need a separate array.

Immutable values (numbers, strings, tuples of immutables) can be shared safely, because nothing can change them in place.

Names and objects

A name is a label stuck on an object, not a box holding a value.

is asks "same object?"; == asks "same value?".

When a change shows up elsewhere

Section

Changing lists

Methods like append and sort change the list in place and return None.

Shallow versus deep copies, and the [[0] * 3] * 3 trap.

An argument is passed as a reference to the caller's object, and a mutable default is shared between calls.

Arrays

A slice of an array is a view; fancy indexing makes a copy.