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.
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.
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.
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?
Reveal 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.
Removing the First Element Without Changing the Caller List
A function attempts to remove the first element by reassigning its parameter to a slice.
- 1Initial state
The caller's list and the function parameter initially refer to the same list object.
- 2Slice creation
The expression t[1:] creates a new list containing all elements except the first.
- 3Local reassignment
The assignment t = t[1:] makes the local parameter refer to the new list.
- 4Caller observation
The caller still has the original list because no operation modified that existing list object.
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.
| Operation category | What happens | Original list |
|---|---|---|
| In-place method | The existing list object is modified | Changes are visible to the caller |
| Slicing | A new list is created | Remains unchanged |
| Plus operator | A new list is created | Remains 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.
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.
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.
- 1Modify in place
Choose an in-place list operation when the caller should see the original list changed.
- 2Return a new list
Choose slicing when the original list should remain unchanged and the function should provide a separate result.
- 3Document the intent
Make the choice clear through the function's naming and documentation.
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 likeA parameter is reassigned to a slice inside a function.
Why it failsSlicing creates a new list, and the assignment changes only what the local parameter refers to.
Do this insteadUse 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 likeUsing a slice when the function is expected to change the caller's list.
Why it failsSlicing leaves the original list unchanged.
Do this insteadUse 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 likeA function uses an in-place method even though callers need the original list unchanged.
Why it failsIn-place methods modify the actual list object and make the change visible to the caller.
Do this insteadUse slicing or the plus operator to create a new list and return it.
Practice the Distinction
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()andpop()modify the existing list object. - Remember that slicing and + create new lists.
- 1A parameter can refer to the caller's list without every operation on the parameter changing that list. In-place methods such as
append()andpop()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()andpop()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.