Concepts / Understanding List Mutability

Understanding List Mutability

The central question is not simply whether a list expression appears inside a function. Ask whether the operation modifies the existing list object or creates a new list and reassigns a variable.

  • Programming

Two Ways a List Can Change

When working with lists, two different events can look similar at first. A function can change the contents of the existing list object, or it can make a local variable refer to a different list. The first kind of change is visible through the caller's list. The second kind changes only the local variable's reference.

Key point

The central question is not simply whether a list expression appears inside a function. Ask whether the operation modifies the existing list object or creates a new list and reassigns a variable.

Rebindingvariable refers to a newlistNew listoriginal list unchangedMutationexisting list contentschangeExisting listcaller observes the changechanges referencechanges contents
What is the difference between changing what a variable refers to and changing the contents of the list it already refers to?

Tracing a Slice Assignment

What do you think happens?

A function receives a list and performs t = t[1:]. What happens to the list in the caller?

  • The caller's list loses its first element

  • The local parameter refers to a new list, while the caller's list stays unchanged

  • Both the caller's list and the local parameter become empty

Reveal answer
Answer:

The local parameter refers to a new list, while the caller's list stays unchanged

The slice creates a new list. Reassigning t changes what the local variable t refers to; it does not modify the original list object.

Suppose a caller provides a list to a function. Inside the function, the parameter initially refers to the list supplied by the caller. The expression t[1:] creates a new list containing the slice, and the assignment t = t[1:] makes the local parameter refer to that new list. The original list passed by the caller is left unchanged.

items[10, 20, 30]t[1:][20, 30]items[10, 20, 30]tsame list as itemstrefers to the sliceparameter initially refers tot[1:] createsassignment makes t refer to
What happens to the caller's list and the local parameter when a function executes t = t[1:]?
Worked example

Removing the First Element Without Changing the Caller List

A function attempts to remove the first element by reassigning its parameter to a slice.

  1. 1
    Initial state

    The caller's list and the function parameter initially refer to the same list object.

  2. 2
    Slice creation

    The expression t[1:] creates a new list containing all elements except the first.

  3. 3
    Local reassignment

    The assignment t = t[1:] makes the local parameter refer to the new list.

  4. 4
    Caller observation

    The caller still has the original list because no operation modified that existing list object.

Result

Reassigning the parameter to a slice does not modify the original list.

Slicing and New List Objects

Slicing is an operation that creates a new list. The new list contains the selected elements, but it is not the original list object. The original remains available through any variable that still refers to it. The plus operator also creates a new list, so using slicing or + does not by itself modify the original list.

Original list[10, 20, 30]Sliced list[20, 30]slice creates
Which list object does a slice refer to before and after the slice operation, and how are the original and new lists related?
Operation categoryWhat happensOriginal list
In-place methodThe existing list object is modifiedChanges are visible to the caller
SlicingA new list is createdRemains unchanged
Plus operatorA new list is createdRemains unchanged

The important distinction is whether the existing list object is modified or a new list is created.

Changing the Existing List

In-place methods operate on the actual list object. Methods such as append() and pop() modify that existing object. If a function parameter refers to the caller's list and the function uses one of these methods, the caller can observe the changed contents after the function finishes.

items[10, 20]items[10, 20, 30]trefers to itemststill refers to itemsappend modifiessame list object
How does an in-place method change the existing list object while preserving the reference held by the caller?
Best practice

Use an in-place method when the function's purpose is to modify the list supplied by its caller. Make that intent clear through the function's naming and documentation so users know that the original list will change.

Designing List Functions

A function that modifies a list and a function that returns a new list have different effects. For the modifying version, use an in-place operation such as append() or pop(). For the non-modifying version, use an operation such as slicing or + and return the resulting new list. The choice should match the function's purpose.

Caller list[10, 20]Function parameterrefers to caller listappend()in-place operationCaller list[10, 20, 30]passes listcalls on listmodifies existing object
How does data move from the caller's list into a function, and which operation causes the caller to observe the modification afterward?
Original list[10, 20, 30]Original list[10, 20, 30]Returned list[20, 30]slicing createsseparate list
What lists exist before and after a function returns, and how can the returned list change while the original remains unchanged?
Worked example

Choosing the Function's Effect

Decide whether a function should use an in-place operation or return a new list when its purpose is to remove the first element.

  1. 1
    Modify in place

    Choose an in-place list operation when the caller should see the original list changed.

  2. 2
    Return a new list

    Choose slicing when the original list should remain unchanged and the function should provide a separate result.

  3. 3
    Document the intent

    Make the choice clear through the function's naming and documentation.

Result

The correct design depends on whether changing the caller's list is part of the function's purpose.

Common Mistakes

  • Common mistake

    Assuming that t = t[1:] removes the first element from the caller's list.

    What it looks like

    A parameter is reassigned to a slice inside a function.

    Why it fails

    Slicing creates a new list, and the assignment changes only what the local parameter refers to.

    Do this instead

    Use an in-place list method when the function must modify the original list.

  • Common mistake

    Treating slicing and in-place methods as equivalent.

    What it looks like

    Using a slice when the function is expected to change the caller's list.

    Why it fails

    Slicing leaves the original list unchanged.

    Do this instead

    Use an operation such as append() or pop() for an in-place change.

  • Common mistake

    Changing a list in place when the function should preserve the original.

    What it looks like

    A function uses an in-place method even though callers need the original list unchanged.

    Why it fails

    In-place methods modify the actual list object and make the change visible to the caller.

    Do this instead

    Use slicing or the plus operator to create a new list and return it.

Practice the Distinction

MEDIUM

For each function design, decide whether it should use an in-place method or create and return a new list. Then explain what the caller's original list will contain after the function finishes.

Hints
  • Ask whether the function's purpose includes changing the caller's list.
  • Remember that append() and pop() modify the existing list object.
  • Remember that slicing and + create new lists.
  1. 1
    A parameter can refer to the caller's list without every operation on the parameter changing that list. In-place methods such as append() and pop() modify the existing list object, so the caller sees the change. Slicing and the plus operator create new lists, so assigning their result changes a variable's reference rather than the original list. Choose the operation that matches the function's intended behavior and make that intent clear through naming and documentation.

Key Takeaways

  • Reassigning a function parameter to a slice changes the local parameter's reference, not the original list.
  • In-place methods such as append() and pop() modify the existing list object.
  • Slicing and the plus operator create new lists and leave the original list unchanged.
  • Choose between mutation and returning a new list according to the function's purpose.
  • Use naming and documentation to make a function's list-changing behavior clear.

Related concepts

More concepts starting with U