Function Arguments and Object Modification
Variables are references to objects in memory, not the objects themselves.
The Shared-List Puzzle
Suppose two variable names refer to one list. If the list changes through one name, should the other name show the change? The answer is yes. The key is to stop thinking of a variable as the object itself. A variable is a reference to an object in memory. When several variables refer to the same object, they provide several ways to reach that one object.
What do you think happens?
A list is associated with two variable names. The list is changed through the first name. What will the second name show?
Reveal answer
Answer: The changed list
Both names refer to the same object, so a change made through one reference is visible through the other.
Tracing a Shared Reference
Object binding is the connection between a variable name and an object. Assigning another variable name to an existing list gives that second name another reference to the same list; it does not create an independent list. Therefore, a modification made through either name changes the one shared object. Every variable that refers to that object then reveals the changed contents.
Two Names Following One Change
Imagine that basket and second_basket both refer to one list containing the items apple and bread. The item cheese is added through basket. What does second_basket refer to afterward?
1. Identify the object: There is one list object containing apple and bread. Both variable names refer to that same object.
2. Apply the change: The list is modified through basket, so the shared list now also contains cheese.
3. Follow the other reference: second_basket still refers to the same list object. It therefore shows the list containing apple, bread, and cheese.
Both variable names reveal the modified shared list.
Arguments Follow References
A function argument follows the same reference idea. When a list is passed to a function, the function parameter refers to the list object supplied by the caller. If the function modifies that list, the caller's variable refers to the modified object afterward. The important question is not only which parameter name is used, but which object that name refers to.
Following a List Through a Function
A caller has a list containing red and blue and passes it to a function. Inside the function, the list is modified by adding green. What does the caller's variable refer to after the function finishes?
1. Start with the caller: The caller's variable refers to one list object containing red and blue.
2. Bind the parameter: The function parameter refers to that same list object while the function runs.
3. Modify the object: The function changes the shared list by adding green.
4. Return to the caller: The caller's variable still refers to the same list object, now containing red, blue, and green.
A function can modify the caller's list when its parameter refers to that same list object.
Making an Independent Copy
When two variable names must refer to independent lists, create a copy rather than assigning another name to the existing list. Full slice notation creates an independent copy. The notation uses the entire list, as in mylist = shoplist[:]. After this operation, shoplist and mylist refer to separate list objects. A modification to one list does not become a modification to the other list through shared reference.
Separating Two Lists
shoplist refers to a list containing notebook and pen. Create an independent list for mylist using full slice notation, then add folder to mylist. What should happen to shoplist?
1. Begin with one list: shoplist refers to the original list containing notebook and pen.
2. Copy the full list: mylist = shoplist[:] creates an independent copy of the list.
3. Modify the copy: Adding folder to mylist changes the copied list.
4. Check the original: shoplist still refers to the original list, so it remains notebook and pen.
mylist contains notebook, pen, and folder, while shoplist remains notebook and pen.
| Operation | References | Effect of modifying one list |
|---|---|---|
| Assign another name to the existing list | Both names refer to the same object | The change is visible through both names |
| Use full slice notation | The original name and new name refer to separate list objects | The change to one list does not change the other list through shared reference |
Mistakes with Shared Objects
Assuming that a second variable automatically creates a new list
Multiple variables can point to one object. A second name does not by itself make the object independent.
Fix:
Use full slice notation when an independent list copy is required.Looking only at the variable name instead of the referenced object
The parameter can refer to the same list object supplied by the caller.
Fix:
Trace which object each variable or parameter refers to before predicting the result.Treating an unexpected change in another variable as random behavior
Both variables may refer to the same object.
Fix:
Check for shared references before searching for a different cause.
The important distinction is whether the list object is shared or independently copied. If several variables refer to one list, a modification is shared. If full slice notation has created an independent copy, modifying that copy does not modify the original list through shared reference.
Reference Tracking Practice
For each situation, identify whether the variables refer to one shared list or to independent lists. Then predict which list shows the modification: two names refer to one list and the list is changed through the first name; a list is copied with full slice notation and the copy is changed; a list is passed to a function and the function modifies the list.
Hints
- Start by identifying the list object, not just the variable names.
- A second reference to an existing list is still connected to that same object.
- Full slice notation creates an independent copy.
- One object can have multiple variable names referring to it.
- A modification through one reference is visible through every reference to that same object.
- A function parameter can refer to the list supplied by the caller.
- Full slice notation, such as mylist = shoplist[:], creates an independent list copy.
- Tracing object references helps prevent unexpected modifications in multiple places.
Key Takeaways
- Variables are references to objects in memory, not the objects themselves.
- Multiple variables can refer to one list, so modifying the list through one variable affects what the others reveal.
- A function parameter can refer to the same list object that the caller supplied.
- Use full slice notation, such as mylist = shoplist[:], to create an independent list copy.
- Reference tracking helps prevent unexpected modifications from appearing in multiple places.