Understanding Mutability and Immutability
Assignment creates a reference to a list, not a copy. Both variables point to the same object, so modifications through one affect the other.
One List, Two Names
A list can have more than one variable name without being copied. When one list variable is assigned to another, assignment creates a reference to the existing list rather than a separate list. The two variables therefore refer to the same list object. This matters whenever one variable modifies the list: the other variable sees that modification too.
What do you think happens?
Suppose original refers to [1, 2, 3] and alias is assigned from original. If the list is modified through alias, what will original refer to?
Reveal answer
Answer: The modified version of the shared list
Assignment creates another reference to the same list object. It does not create a separate copy.
Tracing an Unintended Mutation
Consider the sequence described by the source material: original = [1, 2, 3], followed by alias = original. At this point, original and alias are two names for the same list. If the list is modified through alias, original does not retain an untouched version. It shows the same modification because both names still refer to the shared object.
Copying for Independence
Use copying when two variables must refer to separate lists. The slice notation [:] and the list() constructor create a shallow copy: a new list with the same elements. After copying, modifying one list does not affect the other. This is different from assignment, which gives another variable a reference to the existing list.
| Operation | Result | Effect of modifying one variable |
|---|---|---|
| alias = original | Both variables refer to the same list object | The other variable sees the modification |
| copy = original[:] | copy refers to a new list with the same elements | The original list is not affected |
| copy = list(original) | copy refers to a new list with the same elements | The original list is not affected |
Choosing a Copy Before Editing
You need to preserve an original list while making changes to another list.
Identify the risk: Assigning a second variable directly from the original would make both variables refer to the same list.
Create independence: Use original[:] or list(original) to create a new list with the same elements.
Modify deliberately: Changes made to the copied list do not affect the original list because the copy is a separate list.
Use a copy when the original must remain available for later use. Modify the original directly only when changing it in place is intentional.
Replacing a Slice
Slice assignment uses the form t[start:end] = sequence. It replaces the elements selected by the slice with the values in the replacement sequence. Because several positions can be replaced at once, slice assignment is useful for bulk list modifications.
In this example, the slice t[1:3] refers to ['b', 'c']. Those two elements are replaced by ['x', 'y']. Because the replacement sequence also contains two elements, the list remains six elements long.
Tracking List Length
The replacement sequence does not have to be the same size as the selected slice. If the replacement is shorter than the slice, the list shrinks. If it is longer, the list grows. If both have the same size, the list keeps its length. This size comparison is the key step when predicting the result of slice assignment.
| Selected slice size | Replacement size | Effect on list length |
|---|---|---|
| Same size | Same size | List length stays the same |
| Larger than replacement | Shorter | List shrinks |
| Smaller than replacement | Longer | List grows |
Compare the number of selected elements with the number of replacement values.
A Longer Replacement
A copied list has 5 elements. A slice containing [30, 40] is replaced by [200, 201, 202]. What happens to the list length?
Count the selected elements: The selected slice contains 2 elements: [30, 40].
Count the replacement elements: The replacement sequence contains 3 elements: [200, 201, 202].
Compare the sizes: The replacement is longer by 1 element.
The list grows from 5 elements to 6 elements.
Debugging Shared References
Unintended mutations usually begin with an incorrect assumption: treating assignment as if it copied the list. To debug the problem, trace how each variable was created. If one variable was assigned directly from another list variable, they share one list object. Next, locate the operation that modifies the list, including slice assignment, and determine which other names can see that same object.
Assuming alias = original creates a copy.
Assignment creates a reference to the existing list, so both variables refer to the same object.
Fix:
Use original[:] or list(original) when an independent list is required.Forgetting that a replacement sequence can change list length.
Slice assignment replaces the selected elements with the complete replacement sequence, so a longer replacement grows the list.
Fix:
Count the selected elements and replacement elements before predicting the result.Changing a shared list when the original must be preserved.
The two variables refer to the same list object.
Fix:
Create a shallow copy before modifying the second list.
Be explicit about intent. If later logic needs the original list, make a copy before modifying another version. If changing the original list in place is intentional, document that intent so a future reader does not mistake the shared mutation for a bug.
Practice the Trace
A list has six elements. A slice selects two elements. Predict the list-length change in each case: the replacement has two elements, the replacement has one element, and the replacement has four elements. Then decide whether you would assign a second variable directly or create a copy if the original list must be preserved.
Hints
- Compare the selected slice size with the replacement sequence size.
- Equal sizes preserve length.
- A shorter replacement shrinks the list, and a longer replacement grows it.
- Use [:] or list() when you need an independent list.
- Trace how each variable was created: direct assignment means a shared reference.
- Identify the list operation that changes the object.
- Count the elements selected by the slice.
- Count the elements in the replacement sequence.
- Decide whether the list shrinks, stays the same length, or grows.
- Use [:] or list() first when the original list must remain unchanged.
Key Takeaways
- Assigning one list variable to another creates a shared reference, not a copy.
- Use [:] or list() to create a shallow copy with the same elements and an independent list object.
- Slice assignment replaces multiple elements in an existing list.
- A shorter replacement shrinks the list, an equal-sized replacement preserves its length, and a longer replacement grows it.
- When debugging an unexpected mutation, trace shared references and count both the selected and replacement elements.
Key Takeaways
- Assignment gives another variable a reference to the same list; it does not copy the list.
- A shallow copy made with [:] or list() lets two variables refer to separate list objects with the same elements.
- Slice assignment updates a selected range in place and can replace it with a sequence of a different size.
- Always compare slice size with replacement size to predict whether the list will shrink, stay the same length, or grow.
- When preserving the original matters, copy first and make in-place changes intentional.