Understanding List Mutability
Reassigning a function parameter (e.g., t = t[1:]) does not modify the original list passed to the function; it only changes what the local variable refers to.
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
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.
Initial state: The caller's list and the function parameter initially refer to the same list object.
Slice creation: The expression t[1:] creates a new list containing all elements except the first.
Local reassignment: The assignment t = t[1:] makes the local parameter refer to the new list.
Caller 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 |
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.
Modify in place: Choose an in-place list operation when the caller should see the original list changed.
Return a new list: Choose slicing when the original list should remain unchanged and the function should provide a separate result.
Document 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
Assuming that t = t[1:] removes the first element from the caller's list.
Slicing creates a new list, and the assignment changes only what the local parameter refers to.
Fix:
Use an in-place list method when the function must modify the original list.Treating slicing and in-place methods as equivalent.
Slicing leaves the original list unchanged.
Fix:
Use an operation such as append() or pop() for an in-place change.Changing a list in place when the function should preserve the original.
In-place methods modify the actual list object and make the change visible to the caller.
Fix:
Use 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() and pop() modify the existing list object.
- Remember that slicing and + create new lists.
- 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.