Functions that mutate
A function takes one or more parameters. Some functions will mutate or change their parameters. For example, a function may take a list as a parameter, and then append or remove things from the list, or change items in the list.
In general, when you write a function, it is a good idea to avoid mutating the parameters you are given. Let’s walk through a few examples
Swapping the first and last items in a list
Here is a function that mutates a list — it swaps the first and list items:
def swap_first_and_last(items):
    """Swap the first and last items in the input list. Modify the list in place."""
    first = items[0]
    items[0] = items[-1]
    items[-1] = first
numbers = [1, 2, 3, 4, 5]
swap_first_and_last(numbers)
print(numbers)This will print:
[5, 2, 3, 4, 1]It is generally preferred to write functions that do NOT mutate their inputs. Whenever possible, try to write functions that don’t mutate.
A version that does not mutate the list
For example, this code will also swap the first and last items in a list, but it returns a new list instead of modifying the original list.
def swap_first_and_last(items):
    """Swap the first and last items in the input list. Return a new list."""
    new_items = []
    # append the last item
    new_items.append(items[-1])
    # append the middle items
    for index in range(1, len(items) - 1):
        new_items.append(items[index])
    # append the last item
    new_items.append(items[0])
    return new_items
numbers = [1, 2, 3, 4, 5]
new_numbers = swap_first_and_last(numbers)
print(new_numbers)Be sure to document whether your function mutates its inputs or not. Write non-mutating functions whenever possible.
Reversing a list
Python has a built-in function for reversing a list that mutates the list:
numbers = [3, 4, 10, 7, 1]
numbers.reverse()
print(numbers)This will print:
[1, 7, 10, 4, 3]Let’s write a version that does not mutate the list:
def reverse_list(items):
    "reverse the list, and return a NEW list with the inverted copy"
    new_list = []
    for i in range(len(items)):
        index = -1 - i
        new_list.append(items[index])
    return new_list
numbers = [1, 7, 10, 4, 3]
new_list = reverse_list(numbers)
print(new_list)To reverse the list we need to start with item -1 — the last item in the list
— and then continue with item -2, -3, etc. The index variable will
iterate through this list of numbers, by subtracting i from -1.
So the first time through this loop, we will append item items[-1] to
new_list. The second time we will append items[-2]. And so forth.
Here is a different way to do the same thing:
def invert(items):
    "invert the list, and return a NEW list with the inverted copy"
    new_list = []
    end = -(len(items) + 1)
    for i in range(-1, end, -1):
        new_list.append(items[i])
    return new_listThe value len(items) is 5, so len(items) - 1 equals 6. This means end
equals -6.
Given end, the range() counts from -1 down to -6, subtracting 1 each
time, so it counts: -1, -2, -3, -4, -5. We can then use i to get the item we
need from items and append it to new_list.
Just like above, we will append item items[-1] to new_list. The second time
we will append items[-2]. And so forth.