Understanding List Mutability and References
Aliasing means two variables point to the same list object, so changes through one variable affect the other.
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
- name = object binds a name; b = a makes b point at the same object.
- Mutating a list (append, +=) changes the one shared object.
- a = a + [x] and y = y + 1 create NEW objects and re-point one name.
- 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.
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.
Tracing an Alias
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.
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.
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.
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.
| Tool | Effect on original list | Useful choice when |
|---|---|---|
| sorted() | Does not modify the original | You need a new sorted list and want the original unchanged |
| sort() | Sorts the list in place | You intend to change the list itself |
| t[:] followed by sort() | Sorts the independent copy | You want sort() behavior without changing the original |
Choosing between sorted(), sort(), and sorting a defensive copy
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.
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
Treating an alias as an independent copy
Both variables point to the same list object, so a mutation through one variable affects the other.
Fix:
Use orig = t[:] when you need an independent list.Using sort() when the original list must stay unchanged
sort() changes the list in place.
Fix:
Use ordered = sorted(scores), or copy first and sort the copy.Assuming equal contents prove two lists are the same object
Separate lists can contain equal values without being aliases.
Fix:
Investigate whether the variables share the same list object.Naming a variable sorted
The variable shadows the built-in sorted function.
Fix:
Choose another variable name, such as ordered.
Apply the Choice
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.
Preserving the Original List
Choose a safe way to obtain a sorted version of t without changing t.
Check the requirement: The original list must remain unchanged, so directly using sort() on t is not the appropriate choice.
Choose a new-list operation: sorted(t) is suitable because it produces a new sorted list without modifying the original.
Choose the copy-and-sort alternative: You can also create orig = t[:] and then use sort() on orig, because orig is an independent list.
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
- Aliasing means two variables point to the same list object, so mutation through one variable affects the other.
- Use orig = t[:] to create an independent list that can be modified safely.
- Use sorted() for a new sorted list that leaves the original unchanged.
- Use sort() when changing the existing list in place is intended.
- 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.