Concepts / Understanding List Mutability and References

Understanding List Mutability and References

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

  • 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.

t[1, 2, 3]same list objectaliasrefers torefers to
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.

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

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.

t[3, 1, 2]t[3, 1, 2]orignot createdorig[1, 2, 3]preservedcreated by t[:]
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
sorted()new sorted listscores[3, 1, 2]sort()changes list in placeordered[1, 2, 3]createsleaves unchangedupdates
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.

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

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

  • Common mistake

    Treating an alias as an independent copy

    What it looks like
    alias = t
    Why it fails

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

    Do this instead

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

  • Common mistake

    Using sort() when the original list must stay unchanged

    What it looks like
    scores.sort()
    Why it fails

    sort() changes the list in place.

    Do this instead

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

  • Common mistake

    Assuming equal contents prove two lists are the same object

    What it looks like

    Two variables each show [1, 2].

    Why it fails

    Separate lists can contain equal values without being aliases.

    Do this instead

    Investigate whether the variables share the same list object.

  • Common mistake

    Naming a variable sorted

    What it looks like
    sorted = [1, 2, 3]
    Why it fails

    The variable shadows the built-in sorted function.

    Do this instead

    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.
Worked example

Preserving the Original List

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

  1. 1
    Check the requirement

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

  2. 2
    Choose a new-list operation

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

  3. 3
    Choose the copy-and-sort alternative

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

Result

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. 1
    Aliasing means two variables point to the same list object, so mutation through one variable affects the other.
  2. 2
    Use orig = t[:] to create an independent list that can be modified safely.
  3. 3
    Use sorted() for a new sorted list that leaves the original unchanged.
  4. 4
    Use sort() when changing the existing list in place is intended.
  5. 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.

Related concepts

More concepts starting with U