Concepts / Function Parameters and Scope

Function Parameters and Scope

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.

  • Programming

One List, Two Variables

When a list is passed to a function, the function parameter can refer to the same list object that the caller's variable refers to. The important question is what the function does next. If the function changes the existing list object with an in-place method, the caller can see that change. If the function reassigns the parameter to a new list, the caller's variable continues to refer to the original list.

A parameter is a local variable. Reassigning that local variable changes what the parameter refers to, not what the caller's variable refers to.

refers tobefore reassignmentafter t = t[1:]items[10, 20, 30]t[1:][20, 30]t[10, 20, 30][10, 20, 30]original list
What does the parameter refer to before and after reassignment, and what object does the caller's variable still refer to?

Tracing a Slice Reassignment

What do you think happens?

After remove_first runs, what will numbers contain?

  • [8, 9]
  • [7, 8, 9]
  • The function will return a new list automatically
Reveal answer

Answer: [7, 8, 9]

The expression numbers[1:] creates a new list. The assignment changes the local parameter to refer to that new list, while the caller's variable still refers to the original list.

def remove_first(t): t = t[1:] numbers = [7, 8, 9] remove_first(numbers)

t = t[1:]caller remainst[7, 8, 9][8, 9]new listnumbers[7, 8, 9]
What changes when the function assigns t = t[1:]?

Mutation and New Lists

List operations fall into two useful groups. In-place methods operate on the existing list object. Methods such as append() and pop() modify that object, so a caller can see the result when the function parameter refers to the caller's list. Other operations create a new list. Slicing and the + operator create new lists, leaving the original list unchanged unless the new result is assigned back to the caller's variable or returned and used.

OperationWhat it doesEffect on the original list
append()Modifies the existing list objectThe change is visible to the caller
pop()Modifies the existing list objectThe change is visible to the caller
remove()Modifies the existing list objectThe change is visible to the caller
extend()Modifies the existing list objectThe change is visible to the caller
SlicingCreates a new listThe original remains unchanged
The + operatorCreates a new listThe original remains unchanged
append(4)items[1:]original remainsitems[1, 2, 3]items[1, 2, 3, 4]new list[2, 3]items[1, 2, 3]
Which operations change the existing list object, and which operations create a separate list object?

Choosing the Function’s Effect

Removing the First Item

Create one function that changes the supplied list and another function that produces a list without changing the supplied list.

Modify in place: Use an in-place method when the function's purpose is to change the list supplied by the caller.

Return a new list: Use slicing and return its result when the function's purpose is to produce a separate list while preserving the original.

Make the result explicit: The caller can tell the two purposes apart because one function changes the argument and the other returns a result that the caller can store.

An in-place function changes the caller's list. A function that returns a slice leaves the caller's original list unchanged.

python
Output
[8, 9]
[7, 8, 9]
[8, 9]
function callitems.pop(0)modifiesnumbers[7, 8, 9]items[7, 8, 9]pop(0)in-place method[8, 9]same list object
How does a method such as append, extend, or remove move from the function parameter to the original list object?

Choose the behavior that matches the function's purpose. If a function is intended to update a supplied list, use an in-place method and make that intention clear through its name and documentation. If it is intended to produce another list, return the new list and leave the original unchanged.

Two Lists After a Return

A function can create a new list with slicing and return it. In that case, the caller may keep both the original list and the returned list. The original remains available through the caller's variable, while the returned value refers to the newly created list. This is different from assigning a slice only to a local parameter and then discarding it when the function ends.

python
Output
[4, 5, 6]
[5, 6]
refers toreceives return valueoriginal[4, 5, 6][4, 5, 6]original listresult[5, 6][5, 6]new list
What list objects exist after a function returns a slice, and how is the returned list related to the original?

Common Mistakes

  • Assuming that t = t[1:] edits the caller's list

    Slicing creates a new list, and the assignment changes only the local parameter.

    Fix: Use an in-place method such as pop() when the function should change the supplied list, or return the slice when the function should create a result.

  • Using an in-place method when the original list should remain unchanged

    append() modifies the actual list object, so the caller can see the change.

    Fix: Create and return a new list when preservation of the original is part of the function's purpose.

  • Creating a new list but not returning it

    The new list is assigned to a local parameter and is not made available to the caller.

    Fix: Return the new list and assign the returned value in the caller when that result is needed.

Practice the Decision

MEDIUM

Write two functions for a list named values. The first function should remove the last item from the supplied list by modifying it in place. The second function should return a new list containing all items except the last, without modifying the supplied list.

Hints
  • Use an in-place list method for the first function.
  • Use slicing and return the result for the second function.
  • Test each function with a list and inspect both the original variable and any returned value.
QuestionReassignment to a sliceIn-place mutation
Does it create a new list?YesNo
Does it modify the existing list?NoYes
Does the caller see the original list changed?NoYes
What should the function do if the new list is needed?Return itThe existing list is already changed

Key Takeaways

  1. A function parameter is a local variable that can initially refer to the same list object as the caller's variable.
  2. Reassigning a parameter to a slice changes the local parameter and does not modify the original list.
  3. Methods such as append(), pop(), remove(), and extend() modify the existing list object, making their effects visible to the caller.
  4. Slicing and the + operator create new lists, so return the new list when the caller needs it.
  5. Choose in-place modification or a returned new list according to the function's purpose, and make that choice clear through naming and documentation.

Key Takeaways

  • Reassigning a function parameter does not reassign the caller's variable.
  • A slice creates a new list, while in-place methods modify the existing list.
  • Use methods such as append(), pop(), remove(), or extend() when a function should change the supplied list.
  • Return a sliced or otherwise newly created list when the original should remain unchanged.
  • Function names and documentation should make the intended list behavior clear.