Aliasing and References in Python
Aliasing becomes important when more than one variable name refers to the same mutable list.
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…
The Shared-Collection Problem
Lists and tuples both hold ordered collections of related values, but they support different programming decisions. A list is mutable, so its elements can be added, removed, or changed after creation. A tuple is immutable, so its contents are fixed. The important question is not which type is universally better. The question is whether later code should be allowed to change the collection.
Aliasing becomes important when more than one variable name refers to the same mutable list. If the list is changed through one name, code using another name can observe the changed collection. This flexibility is useful when shared updates are intentional, but it can also create aliasing bugs when a function or part of a program changes data unexpectedly.
Tracing a Mutation
What do you think happens?
Suppose two names refer to one mutable list. If the list is changed through the first name, what should the second name observe?
Reveal answer
The second name observes the changed list.
Both names refer to the same mutable list in this example. Mutating that shared collection changes the state visible through either name.
A Shared List After an Update
Two parts of a program use the same list of tasks. One part adds a new task. What should the other part see?
- 1Initial state
Both names refer to the same mutable collection of tasks.
- 2Mutation
The first part adds an item to the list. Adding an item is one of the changes that lists support after creation.
- 3Observation
The second part sees the added item because it also refers to that shared list.
- 4Design check
This behavior is appropriate when both parts are meant to share updates. It is a liability when the second part was expected to receive protected, unchangeable data.
Use a mutable list when shared changes are intentional; avoid exposing shared mutable state when accidental changes would be difficult to debug.
When Lists Fit
Lists are the default choice for most tasks because they are flexible. Choose a list when a collection must grow, shrink, or have individual elements changed after creation. The source material identifies building a collection of user inputs, accumulating results in a loop, filtering data, and sorting in place as situations where list mutability is useful.
| Task constraint | Better sequence choice | Reason |
|---|---|---|
| The collection must grow or shrink | List | Lists can have elements added or removed after creation. |
| Elements must be changed during processing | List | Lists allow elements to be changed after creation. |
| The collection should remain fixed | Tuple | Tuples are immutable. |
| The collection must be used as a dictionary key | Tuple | Dictionaries require immutable keys. |
| A function should not modify the original data | Tuple | Passing a tuple guarantees that the function cannot modify the original data. |
Choose according to the collection's required behavior, not by habit.
Three Reasons to Choose Tuples
Tuples are not merely lists with a different appearance. Their immutability solves three specific problems. First, tuples must be used as dictionary keys because dictionaries require immutable keys. Second, tuples provide cleaner syntax for returning multiple values from a function. Third, passing a tuple to a function guarantees that the function cannot modify the original data, which prevents a class of aliasing bugs.
Matching the Type to the Constraint
Select a list or tuple for each situation: a fixed group of related values, a collection that must accept new items, a dictionary key, a function input that must not be modified, and a function result containing multiple values.
- 1Fixed group
Choose a tuple because the group is not intended to change.
- 2Growing collection
Choose a list because the task requires adding items.
- 3Dictionary key
Choose a tuple because dictionary keys must be immutable.
- 4Protected function input
Choose a tuple because the called function cannot modify the original tuple data.
- 5Multiple returned values
Choose a tuple when the fixed group of returned values benefits from tuple return syntax.
Tuples are preferable when fixed structure, dictionary-key use, clean multi-value returns, or protection against modification is the important constraint. Lists are preferable when the collection must change.
Selecting Under Constraints
For each task, choose list or tuple and explain the constraint that determines your choice: a collection of user inputs that will grow; a fixed group of related values; a dictionary key; a function input that must not be modified; and a collection that will be filtered and sorted in place.
Hints
- Ask whether the collection must change after creation.
- Remember that dictionary keys must be immutable.
- A tuple can prevent a function from modifying the original data.
Common mistake Choosing a list automatically for every ordered collection
What it looks likeUsing a mutable list for data that should remain fixed or protected from a function
Why it failsThe collection can be changed even though the task does not require mutation, increasing the risk of aliasing bugs.
Do this insteadChoose a tuple when immutability provides a real benefit.
Common mistake Choosing a tuple when the task requires additions or removals
What it looks likeRepresenting a collection that must grow as a tuple
Why it failsTuples are immutable and are not the appropriate tool for a collection that must change.
Do this insteadChoose a list when the collection must grow, shrink, or have elements changed.
Common mistake Trying to use a list as a dictionary key
What it looks likeSelecting a list to represent a key made from multiple related values
Why it failsDictionaries require immutable keys.
Do this insteadUse a tuple for a dictionary key.
Common mistake Ignoring shared mutable state
What it looks likePassing a mutable list through code when the receiving function should not change the original data
Why it failsShared mutable data can lead to aliasing bugs.
Do this insteadPass a tuple when the function must be unable to modify the original data.
Deliberate Sequence Choices
- 1A list is mutable and is the default choice for most tasks.
- 2Aliasing occurs when multiple names refer to shared mutable data, so a mutation through one name can affect what another name observes.
- 3Choose a tuple when the collection should remain fixed or when a function must be unable to modify the original data.
- 4Tuples must be used as dictionary keys because dictionaries require immutable keys.
- 5Tuples also provide cleaner syntax for returning multiple values from a function.
Key Takeaways
- Use a list when a collection must be added to, reduced, or changed.
- Treat mutability as a liability when shared data should not be altered accidentally.
- Use a tuple for fixed data, dictionary keys, protected function inputs, and clean multiple-value returns.
- Make the sequence choice from the task's constraints rather than choosing by habit.