To start this guide, download this zip file.
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
Replacing 2 with 5
Here is a function that mutates a list — it replaces every 2 with a 5. You can
find this code in replace_mutate.py
:
def replace_two_with_five(items: list[int]):
"""
Replace every 2 with a 5. Modify the list in place.
"""
for i in range(len(items)):
if items[i] == 2:
items[i] = 5
if __name__ == '__main__':
numbers = [1, 2, 3, 2]
print("original list:")
print(numbers)
print()
replace_two_with_five(numbers)
print("original list:")
print(numbers)
This will print:
original list:
[1, 2, 3, 2]
original list:
[1, 5, 3, 5]
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 replace every 2 with a 5, but it returns a
new list instead of modifying the original list. You can find this code in
replace_without_mutate.py
:
def replace_two_with_five(items: list[int]) -> list[int]:
"""
Replace every 2 with a 5. Modify the list in place.
"""
new_items = []
for item in items:
if item == 2:
item = 5
new_items.append(item)
return new_items
if __name__ == '__main__':
numbers = [1, 2, 3, 2]
print("original list:")
print(numbers)
print()
new_numbers = replace_two_with_five(numbers)
print("original list:")
print(numbers)
print()
print("new list:")
print(new_numbers)
This will print:
original list:
[1, 2, 3, 2]
original list:
[1, 2, 3, 2]
new list:
[1, 5, 3, 5]
Notice how the original list is unchanged.
Be sure to document whether your function mutates its inputs or not. Write non-mutating functions whenever possible.
Editing words in a phrase
To show you another example of list indexing, here is a small program that replaces words in a phrase. The program works like this:
- a person enters a phrase, containing multiple words (“hello I am pleased to meet you”)
- the program loops for as long as you want
- enter a word (“pleased”)
- enter a replacement word (“thrilled”)
- replace the word with its replacement in the phrase (replace “pleased” with “thrilled” in the phrase)
Here is code to do this, which is in edits.py
:
def replace_word(phrase: list[str], word: str, other: str):
"""
<phrase> should be a list that contains multiple words
<word> and <other> are words
Replace <word> with <other> in <phrase>.
This modifies the list in <phrase>.
"""
for i in range(len(phrase)):
if phrase[i] == word:
phrase[i] = other
def main():
# ask for a phrase (multiple words)
# spilt it into a list of words
phrase = input('Phrase: ').split()
print(phrase)
# ask for a series of <word>s and <replacement>s
# replace each instance of <word> with its <replacement> in the
# phrase
while True:
word = input('Word: ')
if not word:
break
other = input('Replacement: ')
replace_word(phrase, word, other)
print(phrase)
# turn the list of words back into a string
print(' '.join(phrase))
if __name__ == '__main__':
main()
Some things to note:
-
The
replace_word()
function modifies — or mutates — the list it is given. It does not return a new list. -
One of the most common ways you will use
range()
is to loop through all of the items in a list. You can do this by givingrange()
the length of the list:
for i in range(len(phrase)):
If you run this code, you can do something like this:
Phrase: You are doing great with this stuff
['You', 'are', 'doing', 'great', 'with', 'this', 'stuff']
Word: great
Replacement: awesome
['You', 'are', 'doing', 'awesome', 'with', 'this', 'stuff']
Word: stuff
Replacement: class
['You', 'are', 'doing', 'awesome', 'with', 'this', 'class']
Word:
You are doing awesome with this class
Notice how we have put an extra print()
statement in the code so you can see
how the list is being modified each time through the loop.
Scoreboard
We are going to write a game for two teams that has these rules:
- the computer picks a secret number between 1 and 10
- both teams try to guess the secret number
- the team that is closer to the secret gets a point
- if both teams are equally close, they both get a point
- the first team to five points wins
To represent points, we are going to use two emojis:
POINT = '🟩'
NO_POINT = '⬜️'
To represent how many points each team has earned so far, we are going to use a list. This list means a team has scored zero points so far:
['⬜️', '⬜️', '⬜️', '⬜️', '⬜️']
ad this list means a team has scored three points so far:
['🟩', '🟩', '🟩', '⬜️', '⬜️']
Here is a flow chart for this problem:
We can also write this in English:
- create score lists for each team
- while True
- pick a secret number
- get guesses for each team
- add a point for the team that wins (or both if there is a tie)
- if Team 1 has five points
- Team 1 wins!
- break
- if Team 2 has five points
- Team 2 wins!
- break
(You may notice a small issue with this code. If both teams make it to five
points simultaneously, Team 1 wins. With some extra if
statements you could
fix this.)
Here is the code that implements these ideas, which you can find in
scoreboard.py
:
import random
# these are two variables that represent a point and no point
# since the variable names are in uppercase, we know we should
# never change them
POINT = '🟩'
NO_POINT = '⬜️'
def add_point(scores: list[str]):
"""
<scores> is a list of POINT and NO_POINT characters
Change the first NO_POINT in the list to POINT
Modifies the <scores> list.
"""
# loop through all of the characters in <scores>
for i in range(len(scores)):
# if this character is NO_POINT, change it to
# POINT and return
if scores[i] == NO_POINT:
scores[i] = POINT
return
def main():
# create a list of 5 NO_POINT characters, representing
# give empty
# each list will look like this:
# ['⬜️', '⬜️', '⬜️', '⬜️', '⬜️']
team1_score = [NO_POINT] * 5
team2_score = [NO_POINT] * 5
while True:
# choose a random number between 1 and 10
secret = random.randint(1, 10)
# decide which team goes first using a random number
# between 0 and 1. 50% of the time team 1 will go first,
# and 50% of teh time team 2 will go first
if random.random() < 0.5:
team1_guess = int(input('Team 1 guess: '))
team2_guess = int(input('Team 2 guess: '))
else:
team2_guess = int(input('Team 2 guess: '))
team1_guess = int(input('Team 1 guess: '))
print(f"The secret number was {secret}")
# calculate how far off each team was
diff1 = abs(team1_guess - secret)
diff2 = abs(team2_guess - secret)
if diff1 < diff2:
# if team 1 was closer, they get a point
add_point(team1_score)
elif diff2 < diff1:
# if team 2 was closer, they get a point
add_point(team2_score)
else:
# if both teams were equally close, they both get a point
add_point(team1_score)
add_point(team2_score)
# print the scores
print(f'Team 1: {team1_score}')
print(f'Team 2: {team2_score}')
# first team to five points wins
# we can check if a team has five points by checking if
# the last character in the list is equal to POINT
if team1_score[-1] == POINT:
print('Team 1 wins!')
break
if team2_score[-1] == POINT:
print('Team 2 wins!')
break
if __name__ == '__main__':
main()
If you run this code, you should see something like this:
Team 2 guess: 5
Team 1 guess: 4
The secret number was 8
Team 1: ['⬜️', '⬜️', '⬜️', '⬜️', '⬜️']
Team 2: ['🟩', '⬜️', '⬜️', '⬜️', '⬜️']
Team 2 guess: 7
Team 1 guess: 6
The secret number was 9
Team 1: ['⬜️', '⬜️', '⬜️', '⬜️', '⬜️']
Team 2: ['🟩', '🟩', '⬜️', '⬜️', '⬜️']
Team 1 guess: 3
Team 2 guess: 4
The secret number was 5
Team 1: ['⬜️', '⬜️', '⬜️', '⬜️', '⬜️']
Team 2: ['🟩', '🟩', '🟩', '⬜️', '⬜️']
Team 2 guess: 8
Team 1 guess: 7
The secret number was 10
Team 1: ['⬜️', '⬜️', '⬜️', '⬜️', '⬜️']
Team 2: ['🟩', '🟩', '🟩', '🟩', '⬜️']
Team 2 guess: 5
Team 1 guess: 6
The secret number was 6
Team 1: ['🟩', '⬜️', '⬜️', '⬜️', '⬜️']
Team 2: ['🟩', '🟩', '🟩', '🟩', '⬜️']
Team 1 guess: 5
Team 2 guess: 4
The secret number was 5
Team 1: ['🟩', '🟩', '⬜️', '⬜️', '⬜️']
Team 2: ['🟩', '🟩', '🟩', '🟩', '⬜️']
Team 2 guess: 5
Team 1 guess: 6
The secret number was 10
Team 1: ['🟩', '🟩', '🟩', '⬜️', '⬜️']
Team 2: ['🟩', '🟩', '🟩', '🟩', '⬜️']
Team 2 guess: 3
Team 1 guess: 4
The secret number was 1
Team 1: ['🟩', '🟩', '🟩', '⬜️', '⬜️']
Team 2: ['🟩', '🟩', '🟩', '🟩', '🟩']
Team 2 wins!