Concepts / Understanding List Mutability and References

Understanding List Mutability and References

Aliasing means two variables point to the same list object, so changes through one variable affect the other.

  • Programming
Interactive lab

Try it: Names and Objects

How Python variables are names bound to objects: assignment never copies, mutating a list is seen through every name that points at it, and ints are replaced rather than changed.

How it works

  1. name = object binds a name; b = a makes b point at the same object.
  2. Mutating a list (append, +=) changes the one shared object.
  3. a = a + [x] and y = y + 1 create NEW objects and re-point one name.
  4. Passing a list to a function passes the reference, so the function can change it.

Default run (7 steps): Two names, one list. Every name is a label that points at an object. … Printed: [1, 2, 3] / True

Simplified: Six fixed scripts on a tiny heap; you choose the values. Object numbers are illustrative, not real id() values.

Educational simulation

Loading the simulation…

One Change, Two Views

A list can be accessed through more than one variable. When two variables point to the same list object, the variables are aliases. A mutation made through one variable affects what is seen through the other variable because both names refer to the same list.

refers torefers tot[1, 2, 3]same list objectalias
What happens to both variables when a list is mutated through only one of them?

Tracing an Alias

python

Here, alias refers to the same list object as t. The append operation is made through alias, but the list viewed through t also changes. The important distinction is between changing the existing list and assigning a different list to a variable. Aliasing matters when the existing list is mutated.

mutation observedmutation made heret[1, 2, 3]t[1, 2, 3, 4]alias[1, 2, 3]alias[1, 2, 3, 4]
How does a mutation travel through multiple references to the same list, and what stays unchanged when a new list is assigned instead?

If an unexpected list change appears in two variables, check whether the variables are aliases before looking for a sorting or indexing mistake.

Slicing for Independence

When you need a separate list that can be modified without changing the original list, create a defensive copy with orig = t[:]. This slicing operation gives orig an independent list. Later mutations made to the copied list can therefore be handled separately from the original data.

python

The key step is t[:]. It creates a separate list rather than another variable referring to the same list object. This makes slicing useful when the original data must be preserved while a working copy is changed.

preservedcreated by t[:]t[3, 1, 2]t[3, 1, 2]orignot createdorig[1, 2, 3]
How does slicing create a new list object, and which changes remain isolated from the original?

Sorting Without Losing Data

Use sorted() when you want a new sorted list without modifying the original. Use the sort() method when you want to sort a list in place. If the original must remain available, another option is to create a defensive copy with slicing and then use sort() on that copy.

ToolEffect on original listUseful choice when
sorted()Does not modify the originalYou need a new sorted list and want the original unchanged
sort()Sorts the list in placeYou intend to change the list itself
t[:] followed by sort()Sorts the independent copyYou want sort() behavior without changing the original

Choosing between sorted(), sort(), and sorting a defensive copy

python
createsleaves unchangedupdatessorted()new sorted listscores[3, 1, 2]sort()changes list in placeordered[1, 2, 3]
Which list changes in place, which returns a new list, and what values remain available after each operation?

Reference Checks

To investigate a suspected alias, compare whether two variables refer to the same list object rather than relying only on whether their contents look equal. Two separate lists can contain the same values, while aliases share the same list object. This distinction explains why mutating one variable can affect the other.

refers torefers torefers torefers toa[1, 2]list objectone objectc[1, 2]list objectobject oneb[1, 2]d[1, 2]list objectobject two
How can we tell whether two variables point to the same list object or to separate lists with equal contents?

When debugging an unexpected change, trace every variable that may refer to the list. If independent data is required, make the relationship explicit with orig = t[:] before modifying the working list.

Common Reference Mistakes

  • Treating an alias as an independent copy

    Both variables point to the same list object, so a mutation through one variable affects the other.

    Fix: Use orig = t[:] when you need an independent list.

  • Using sort() when the original list must stay unchanged

    sort() changes the list in place.

    Fix: Use ordered = sorted(scores), or copy first and sort the copy.

  • Assuming equal contents prove two lists are the same object

    Separate lists can contain equal values without being aliases.

    Fix: Investigate whether the variables share the same list object.

  • Naming a variable sorted

    The variable shadows the built-in sorted function.

    Fix: Choose another variable name, such as ordered.

Apply the Choice

MEDIUM

You have a list named t. You need an ordered version for further work, but you must preserve the original order in t. Which approach should you choose: sorted(t), t.sort(), or orig = t[:] followed by orig.sort()? Explain why.

Hints
  • Ask whether t itself is allowed to change.
  • Remember that sorted() creates a new sorted list.
  • Remember that t[:] creates an independent list.

Preserving the Original List

Choose a safe way to obtain a sorted version of t without changing t.

Check the requirement: The original list must remain unchanged, so directly using sort() on t is not the appropriate choice.

Choose a new-list operation: sorted(t) is suitable because it produces a new sorted list without modifying the original.

Choose the copy-and-sort alternative: You can also create orig = t[:] and then use sort() on orig, because orig is an independent list.

Use sorted(t) when you want a new sorted list directly, or use t[:] before sort() when you want to sort a defensive copy.

Working Rule

  1. Aliasing means two variables point to the same list object, so mutation through one variable affects the other.
  2. Use orig = t[:] to create an independent list that can be modified safely.
  3. Use sorted() for a new sorted list that leaves the original unchanged.
  4. Use sort() when changing the existing list in place is intended.
  5. Avoid sorted as a variable name because it shadows the built-in function.

Key Takeaways

  • Aliasing makes two variables views of the same list object.
  • Mutating an aliased list affects every variable that refers to that object.
  • Slicing with t[:] creates a defensive copy for independent changes.
  • sorted() returns a new sorted list, while sort() changes a list in place.
  • Never use sorted as a variable name because it shadows the built-in function.