0% found this document useful (0 votes)
13 views25 pages

03 Functions

The document provides an overview of functions in Python, emphasizing their importance for writing reusable and reproducible code. It covers the anatomy of a standard Python function, including function definition, parameters, return types, and docstrings, along with best practices and common pitfalls. Additionally, it includes examples and challenges to reinforce understanding of function creation and usage.

Uploaded by

reza fahimi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views25 pages

03 Functions

The document provides an overview of functions in Python, emphasizing their importance for writing reusable and reproducible code. It covers the anatomy of a standard Python function, including function definition, parameters, return types, and docstrings, along with best practices and common pitfalls. Additionally, it includes examples and challenges to reinforce understanding of function creation and usage.

Uploaded by

reza fahimi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 25

03-Functions

December 11, 2023

1 Functions
Functions are essential to wiriting good reproducable code. Functions allow you to reuse and repeat
sections of code without writing the same line multiple times. Objectives: - Learn the atonomy of
a standard python function. - Write and (re)use a function to simplify code. - Use functions to
power up our list comprhensions. - Write functions using keywords

1.1 Example
Let’s jump in with a simple python function then pick it apart line by line.
[1]: ### This is the function definition

def get_abs_difference(input_one: float, input_two: float) -> float:


""" This function calculates the absolute difference between two input␣
↪floats.

Parameters
----------
input_one : float
A float number.
input_two : float
A float number.

Returns
-------
float
The absoloute diffrence between input_one and input_two.
"""
if input_one < input_two:
output = input_two - input_one
elif input_one > input_two:
output = input_one - input_two
else:
output = 0.
return output

[2]: # Once defined we can use the function again and again

1
output1 = get_abs_difference(2.71828, 1.4142)
print(output1)

output2 = get_abs_difference(0.7071, 1.602)


print(output2)

output3 = get_abs_difference(1.3807, -23.0)


print(output3)

output4 = get_abs_difference(3.14159, 3.14159)


print(output4)

1.3040800000000001
0.8949000000000001
24.3807
0.0

Breakdown:

First Line The first line is the most important line of the function, it contains a lot of information
about what the function is going to do.
Here is the first line of the example function:

def get_abs_difference(input_one: float, input_two: float) -> float:


#^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^ ^^^^^^^^
#^^, Function name, Input name, Type hint, Return Type
#Function keyword ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Function arguments (here there are two)
Breaking down the elements:
• Function keyword: def is the keyword that tells the interpreter that we are defining a function.
• Function name: This is the name which we will use to call the function.
• Function Arguments: These are variables you pass to your function there are two here but
we can have 0 to as many as makes sense. Each argument has two parts:
– Input name: This is the name we give to an input, within the function it will act like
varibles we are already used to.
– Type hint: Tells users (and the computer) know what type the input is meant to be.
This isn’t strictly required but highly reccomendeded.
• Return type: Tells users (and the computer) know what type the return is meant to be.

Docstring The next part of the function is called the docstring.

""" This function calculates the absolute difference between two input floats.
Parameters
----------
input_one : float

2
A float number.
input_two : float
A float number.

Returns
-------
float
The absoloute diffrence between input_one and input_two.
"""
Note the docstring here follows the numpydoc format, many projects will have their own formats.
If working on a joint project then use whatever is already in place.
The docstring is the main documentation of the function. The docstring starts with tripple double
quotes """. Immediatly following that is a description of the function, this is desinged to help users
of the function to understand its purpose.
Next in the docstring comes the Parameters. Here we list each of the input variables, the variables
inside the brackets.
input_one : float
First up is the variable name then a colon then the variable type.
The next line is a description of the input.
Finally come the Returns
The first line is the type of the return then the next line is a description of what the function
returns.
There is far more that can go in a docstring but as this is a beginner course we will leave it to just
these three basics

Code The internal code of your function is indented by one block. It will use your arguments to
do some calculation or task that you will want to repeat many times.
In our example is calculates the absolute diffrence between two inputs.

return The final line of a python function will be a return. return tells Python that you are
done and to send the value passed to it back to the main program.

Calling To call a function you simply type the function name followed by brackets containing
the input arguments (if there are any).
get_abs_difference(a, b)
if you want to assign the output of the function to a variable that is as like assigning any other
variable.
function_output = get_abs_difference(a, b)

3
1.1.1 Some rules that are not really rules
Functions are extremely versatile, this versatility is great for experanced programmers who are able
to get functions to behave in ways that let them program efficantly. However, for most programmers
espicially new programmers this versitility can be a curse. Without the expereance of programming
that takes years to build and mature, the risk of side effects & unintended consequences becomes
more likely. For this reason, we are going to define a set of restrictive guidlines that you should not
break until you are much more confident, or even better never.

Rule 1, how to return

a) A function returns a single varable / object. In python a function return is very flexible,
it can return a whole collection of objects for example.

def return_one_two_boo() -> tuple:


""" A function that breaks the rules regarding a single return type
Returns
-------
int, int, str
a tuple of the above type
"""

return 1, 2, 'boo'

one, two, boo = return_one_two_boo()

print(one, two, boo)


This is perfectly valid Python code, the return statment returns all the values after it (note the
comma seperation). Then then we call the function we remember to give enough variables to catch
all the outputs. If we gave the wrong number it would throw an error, if we gave one it would pack
all the outputs into that one variable as a tuple (which is a type we havent covered yet). Also note
that we havent been able to provide useful output type hint as the output type is complicated.
However it adds a layer of complexity that at this stage isn’t useful. This rule is easy enough to
break by returning a list or intentionally returning a tuple as long ag you follow Rule 1b.

b) A function has a single exit point Another counter example showing valid Python that
you shouldnt do.

def one_or_two_or_boo(my_input: int) -> int:


""" A function that breaks the rules about a single point of return
Parameters
----------
my_input: str
an input that is tested by the conditions to determine the output

Returns

4
-------
int or str
either an int or a string 1,2,or boo. Also will print "HELLO WORLD" or just "HELLO" or

"""
if my_input == 1:
return 1
print("HELLO")
if my_input == 2:
return 2
print("WORLD")
return 'boo'
Agian valid Python code. However, the return type hint isn’t strictly correct and a user who came
across this function could get a string. Furthermore the function will print some subset of ‘HELLO
WORLD’ or nothing.

Challange: Provide a single point of return and a single return type. In the cell below
modify the function so it returns a string and only has a single point of return
Hint 1 single point of return
We can use a variable in each of the if statments to collect the output then return that variable at
the end of the function.
Hint 2 single return type
The type that can store 1 or 2 or boo is a string so we can return either “1” or “2” or “boo”
Hint 3
Set the output variable to “boo” then change it to “1” or “2” in the if statements.
[ ]: def one_or_two_or_boo(my_input: int) -> int:
""" A function that breaks the rules about a single point of return
Parameters
----------
my_input: str
an input that is tested by the conditions to determine the output

Returns
-------
int or str
either an int or a string 1,2,or boo. Also will print "HELLO WORLD" or␣
↪just "HELLO" or nothing!

"""
if my_input == 1:
return 1
print("HELLO")
if my_input == 2:

5
return 2
print("WORLD")
return 'boo'

# Don't edit below this line


from example_helpers import check_1_2_boo
check_1_2_boo(one_or_two_or_boo)

Solution One or Two or Boo Solution


Did you remember to update the docstring and type hints?

def one_or_two_or_boo(my_input: int) -> str:


""" If the input is 1 or 2 return this as a string else return 'boo'. Meanwhile also print
Parameters
----------
my_input: int
an input that is tested by the conditions to determine the output.

Returns
-------
str
The string "1" or "2" or "boo"

"""
my_output = "boo"
if my_input == 1:
my_output = "1"
print("HELLO")
if my_input == 2:
my_output = "2"
print("WORLD")
return my_output

Rule 2, Functions return or mutate, never both. When you pass an argument to a function
we expect that argument to be used. However, python can do this in one of two ways.
Return a new value:
def return_new_list(input_list: list, input_item: int) -> list:
""" Append the input_item to the input_list.
Parameters
----------
input_list : list
list to add a value to.
input_item : int
integer to add to the list

6
Returns
-------
list
input_list with the input item added to the end

"""
return input_list + [input_item]

list_to_change = [1,2,3]
list_to_change = return_new_list(list_to_change, 4)
print(list_to_change)
Mutate the value:
def append_item_to_list(input_list: list, input_item: int) -> None:
""" Append the input_item to the input_list.
Parameters
----------
input_list : list
list to add a value to.
input_item : int
integer to append to the list
"""
input_list.append(input_item)

list_to_change = [1,2,3]
append_item_to_list(list_to_change, 4)
print(list_to_change)
These represent the two patterns to follow. Note the return type in the function that mutates is
None. If a function mutates it’s input then it dosen’t specify a return and returns None by default.

Rule 3, No side effects. This rule follows from Rule 2. Functions should do one thing. What
they do can be complicated but it shouldent come with ‘side effects’ lets look at an example of a
function with a side effect.

def append_item_to_list(input_list, input_item):


""" Append the input_item to the input_list.
Parameters
----------
input_list : list
list to add a value to.
input_item : int
integer to append to the list
"""

7
input_list.append(input_item)
# Update list length
global list_length
list_length +=1

list_in = [1,2,3]
list_length = 3

print("List before:", list_in)


print("List length before:", list_length)

append_item_to_list(list_in, 4)

print("List after:", list_in)


print("List length after:", list_length)
Produces the output
List before: [1, 2, 3]
List length before: 3
List after: [1, 2, 3, 4]
List length after: 4
Ignore the global keyword for now it’s another thing best avoided.
The list here has been updated as previously but we introduced a side affect that the variable
list_length has also been updated. This creates a side effect not documented in the function and
makes the function less intuative to it’s exact use.

Summary The three rules above can all be broken in certian circumstances. However, if followed
they will protect the novice programmer from writing code that is difficult to understand or use.
Furthermore, in the majority of cases where a programmer may want to do one of the above there
is ususally a better way to do so. Following these rules will thus motivate finding better ways to
write code and engourage good practice.

1.1.2 Challange
Write functions to meet the following.
1: Checks a number for fizz and returns True if the number is fizz but False if also buzz or neither.
Name the function check_fizz.
2: Checks a number for buzz and returns True if the number is buzz but Flase if also fizz or neither.
Name the function check_buzz.
3: Checks if a number is fizzbuzz and returns True if the number is fizzbuzz but False otherwise.
Name the function check_fizzbuzz.
Hint 1, first line of check_fizz

def check_fizz(number_to_check: int) -> bool:

8
Hint 2, second part of check_fizz

def check_fizz(number_to_check: int) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
Returns
-------
bool
True if number is fizz but not buzz.
"""
Hint 3, full check_fizz

def check_fizz(number_to_check: int) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
Returns
-------
bool
True if number is fizz but not buzz.
"""
if number_to_check % 3 == 0:
output = True
else:
output = False

if number_to_check % 5 == 0:
output = False

return output
Hint 4, how to adapt check_fizz to check_buzz and check_fizzbuzz
To check for buzz switch the 3 and the 5.
To check for fizzbuzz we only need the first if else and the condition should read number_to_check
% 15 == 15
Don’t forget to update the docstring.

9
[ ]: #Do not edit below this line
from example_helpers import check_functions
check_functions(check_fizz, check_buzz, check_fizzbuzz)

Dropdown Template

def check_fizz(number_to_check: int) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
Returns
-------
bool
True if number is fizz but not buzz.
"""
if number_to_check % 3 == 0:
output = True
else:
output = False

if number_to_check % 5 == 0:
output = False

return output

def check_buzz(number_to_check: int) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
Returns
-------
bool
True if number is fizz but not buzz.
"""
if number_to_check % 5 == 0:
output = True
else:
output = False

if number_to_check % 2 == 0:
output = False

return output

10
def check_fizzbuzz(number_to_check: int) -> bool:
""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
Returns
-------
bool
True if number is fizz but not buzz.
"""
if number_to_check % 15 == 0:
output = True
else:
output = False

return output

1.2 Using Functions


We can use functions to improve some of the workflows we have used previously.
Recalling the solution to fizzbuzz in list comprhensions:
fizzed = [i if i%3 else 'fizz'
for i in range(1,101)]

fizzed_then_buzzed = [j_value if (j+1)%5 else 'buzz'


for j, j_value in enumerate(fizzed)]

fizzbuzz_list_comp = ['fizzbuzz' if ((k+1)%3==0 and (k+1)%5==0) else k_value


for k, k_value in enumerate(fizzed_then_buzzed)
]
We can simplify this enormously removing the need for enumerate.
fizzed = ['fizz' if check_fizz(i) else i
for i in range(1,101)]

fizzed_then_buzzed = ['buzz' if check_buzz(j) else j


for j in fizzed]

fizzbuzz_list_comp = ['fizzbuzz' if check_fizzbuzz(k) else k_value


for k in fizzed_then_buzzed]

11
2 Write the code to furfill this functions docstring.
Try to avoid rewriting logical tests by using the functions, check_fizz, check_buzz, and
check_fizzbuzz.
Hint 0, everyone will need to know this! Use the function len. Example:
my_list = [i for i in range(1,51)]
length_of_my_list = len(my_list)
print(length_of_my_list)
The result will be 50. len is a function that returns the length of lists! DO NOT USE enumerate
more on this in the solution.
Hint 1, loop structure
We need to loop over each element of list_in. We can use the following for i in range(0,
len(list_in)):
Hint 2, conditional structure
Use an if, elif, elif pattern to check the list element for fizzbuzzyness
Hint 3, updating list elements
Update the list element using list_in[i] = "thing"
Hint 4, fill in the blanks
[ ]: def check_fizz(number_to_check: int) -> bool:
""" This function checks if a number is fizz but not buzz, i.e. number is a␣
↪multiple of 3 but not 5, and returns True if it is.

Paramaters
----------
number_to_check : int
input integer to check for fizz
Returns
-------
bool
True if number is fizz but not buzz.
"""
if number_to_check % 3 == 0:
output = True
else:
output = False

if number_to_check % 5 == 0:
output = False

return output

def check_buzz(number_to_check: int) -> bool:

12
""" This function checks if a number is fizz but not buzz, i.e. number is a␣
↪multiple of 3 but not 5, and returns True if it is.
Paramaters
----------
number_to_check : int
input integer to check for fizz
Returns
-------
bool
True if number is fizz but not buzz.
"""
if number_to_check % 5 == 0:
output = True
else:
output = False

if number_to_check % 3 == 0:
output = False

return output

def check_fizzbuzz(number_to_check: int) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a␣
↪multiple of 3 but not 5, and returns True if it is.

Paramaters
----------
number_to_check : int
input integer to check for fizz
Returns
-------
bool
True if number is fizz but not buzz.
"""
if number_to_check % 15 == 0:
output = True
else:
output = False

return output

[3]: # Dont edit the code below this line, however you may now be starting to␣
↪understand what is going on here

from example_helpers import check_fizzbuzz as helper_check_fizzbuzz # Grab some␣


↪helper functions that provide automatic feedback to the challanges

list_to_mutate = [i for i in range(1,51)] # Create a list to mutate


fizzbuzz(list_to_mutate) # This calls the fizzbuzz function

13
helper_check_fizzbuzz(list_to_mutate, len(list_to_mutate)) # This checks the␣
↪list the function mutated, to see if the code did the correct thing and␣

↪prints helpful messages

---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[3], line 4
2 from example_helpers import check_fizzbuzz as helper_check_fizzbuzz #␣
↪Grab some helper functions that provide automatic feedback to the challanges

3 list_to_mutate = [i for i in range(1,51)] # Create a list to mutate


----> 4 fizzbuzz(list_to_mutate) # This calls the fizzbuzz function
5 helper_check_fizzbuzz(list_to_mutate, len(list_to_mutate))

NameError: name 'fizzbuzz' is not defined

Solution
def fizzbuzz(list_in: list) -> None:
""" This function mutates list_in fizzing, buzzing, or fizzbuzzing the array elements.
Parameters
----------
list_in : list
A list of int values, this list will be mutated to a fizzbuzzed list.
"""
for i in range(0, len(list_in)):
if check_fizzbuzz(list_in[i]):
list_in[i] = 'fizzbuzz'
elif check_fizz(list_in[i]):
list_in[i] = 'fizz'
elif check_buzz(list_in[i]):
list_in[i] = 'buzz'
This is the neatest solution so far however there are a few pitfalls we should be aware of.
Why did I warn you not to use enumerate, and why do I use for i in range(1, len(list_in))
and not for i in list_in
This comes down to a simple rule that you should not modify the thing you are iterating. Doing
so will remove the ability for the interpreter to do any kind of intelligent speedup and worse could
cause unintended behaviours during the loop.
Specifically: - enumerate(list_in) iterates over list_in. - for i in list_in iterates over
list_in.
Whereas range(len(list_in)) queries list in once to get it’s length then the loop iterates over
range which is seperate from the list.

More on function arguments So far we have been using what are called positional arguments.
Functions have a second type of argument called a keyword argument.

14
def my_keyworded_function(argument_1, argument_2='world'):
print("Positional input:", input_1)
print("Keyword input:", input_2)

my_keyworded_function('Hello')
This would return:
Positional input: Hello
Keyword input: world
This is because the keyword argument has a default value associated with it.
my_keyword_function('Hello', argument_2='Universe')
This would return:
Positional input: Hello
Keyword input: Universe
Also:
my_keyword_function('Goodbye')
This would return:
Positional input: Goodbye
Keyword input: World
Finally:
my_keyword_function(argument_1='Goodbye', argument_2='Universe')
This would return:
Positional input: Goodbye
Keyword input: Universe
We can use the names of positional arguments if we know them.
Another thing to note is that positional arguments come first followed by keyword arguments.

2.0.1 Challange: Write a keyworded version of fizzbuzz


We want a function that obeys the following criteria:
• The default behaviour must be classic fizzbuzz.
• The posititional arguments must be the input list.
• The keyword argumets must be:
– The value to fizz.
– The value to buzz.
– The string to replace the number with for fizz.
– The string to replace the number to buzz.
Provided in the next cell is function definition (1st line) for the function def to start working with.
Hint 1: Some more function definitions

15
It is likely you will want to use all of these in your answer.

def keyword_check_fizz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:

def keyword_check_buzz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:

def keyword_check_fizzbuzz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:


Hint 2: Defs and docstrings
def keyword_check_fizz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:
""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
bool
True if number passes fizz check but not buzz check.
"""
def keyword_check_buzz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:
""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
bool
True if number passes buzz check but not fizz check.
"""

def keyword_check_fizzbuzz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------

16
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
bool
True if number passes fizz and buzz check.
"""

def keyword_fizzbuzz(list_to_mutate: list, fizz_num: int = 3, buzz_num: int = 5, fizz_word: str


""" This function takes a list of numbers and mutates it to replace numbers that are multip
Paramaters
----------
list_to_mutate : list
input list of numbers to mutate
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
None
This function does not return anything, but mutates the list_to_mutate in place.
"""
Hint 3: Where to look for inspration
The solution looks very simmilar to the previous solutions you can copy paste and make alterations.
Hint 4: Full code for fizz
def keyword_check_fizz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:
""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------

17
bool
True if number passes fizz check but not buzz check.
"""
if number_to_check % fizz_num == 0:
output = True
else:
output = False

if number_to_check % buzz_num == 0:
output = False

return output

2.0.2 Bonus Challange (Hard)


Challange for the foolhardy:
• Provide keyword arguments that modify the conditions i.e. don’t just test for x % y
You will not want to use the provided function definitions and there will be no error checking but
do share your solution.
Hint
You can pass functions as arguments
</details>
[ ]: # Do not edit below this line
from example_helpers import check_keyword_fizzbuzz
check_keyword_fizzbuzz(keyword_fizzbuzz) # This sends the keyword_fizzbuzz␣
↪function away to be tested

2.0.3 Answers
Solution to keyword_fizzbuzz

def keyword_check_fizz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
bool

18
True if number passes fizz check but not buzz check.
"""
if number_to_check % fizz_num == 0:
output = True
else:
output = False

if number_to_check % buzz_num == 0:
output = False

return output

def keyword_check_buzz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
bool
True if number passes buzz check but not fizz check.
"""
if number_to_check % buzz_num == 0:
output = True
else:
output = False

if number_to_check % fizz_num == 0:
output = False

return output

def keyword_check_fizzbuzz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5) -> bool:


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

19
Returns
-------
bool
True if number passes fizz and buzz check.
"""
if number_to_check % fizz_num == 0:
output = True
else:
output = False

if number_to_check % buzz_num == 0:
output = True
else:
output = False

return output

def keyword_fizzbuzz(list_to_mutate: list, fizz_num: int = 3, buzz_num: int = 5, fizz_word: str


""" This function takes a list of numbers and mutates it to replace numbers that are multip
Paramaters
----------
list_to_mutate : list
input list of numbers to mutate
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
None
This function does not return anything, but mutates the list_to_mutate in place.
"""
for i in range(len(list_to_mutate)):
if keyword_check_fizzbuzz(list_to_mutate[i], fizz_num=fizz_num, buzz_num=buzz_num):
list_to_mutate[i] = fizz_word + buzz_word
elif keyword_check_fizz(list_to_mutate[i], fizz_num=fizz_num, buzz_num=buzz_num):
list_to_mutate[i] = fizz_word
elif keyword_check_buzz(list_to_mutate[i], fizz_num=fizz_num, buzz_num=buzz_num):
list_to_mutate[i] = buzz_word
Solution to the extra challange
Note this can be done in many ways but I went with this:
So I am passing functions to functions and useing a dictonary which you havent even seen yet to
make an convieniant lookup table.
If you got anything that works thats brilliant.

20
from typing import Callable

def check_if_number_appears_in_first_n_digits_of_pi(a, n):


""" This function checks if a number is in the first n digits of pi. (Where n is less than
Parameters
----------
a : int
The number to check.
Returns
-------
bool
True if a is in the first n digits of pi.
"""
import math

assert n <= 16, "n must be 16 or less"

def create_pi_set(test_len, n):


pi_str = str(math.pi.__round__(n+1))
pi_str = pi_str.replace('.', '')
pi_str = pi_str[0:n]
pi_set = set()
for i in range(0, len(pi_str)-test_len+1):
pi_set.add(pi_str[i:i+test_len])
return pi_set

test_str = str(a)
pi_set = create_pi_set(len(test_str), n)

if test_str in pi_set:
output = True
else:
output = False
return output

def check_if_triangle_number(a, b):


""" This function checks if the number a is in the first b triangle numbers.
Parameters
----------
a : int
The number to check.
b : int
How many triangle numbers to check against.
Returns
-------

21
bool
True if a is a triangle number.
"""
output = False
for i in range(1, b+1):
if a == (i*(i+1))/2:
output = True
return output

def mod_eq_0(a, b):


""" This function checks if a is a multiple of b.
Parameters
----------
a : int
The number to check.
b : int
The number to check against.
Returns
-------
bool
True if a is a multiple of b.
"""
return a % b == 0

# Convinience dictionary to map strings to functions


fun_fizzzbuzz_funs = {
'%' : mod_eq_0,
'triangle': check_if_triangle_number,
'pi': check_if_number_appears_in_first_n_digits_of_pi,
}

def keyword_check_fizz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5, fizz_conditi


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
bool
True if number passes fizz check but not buzz check.
"""
if fizz_condition(number_to_check, fizz_num):

22
output = True
else:
output = False

if buzz_condition(number_to_check, buzz_num):
output = False

return output

def keyword_check_buzz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5, fizz_conditi


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
bool
True if number passes buzz check but not fizz check.
"""
if buzz_condition(number_to_check, buzz_num):
output = True
else:
output = False

if fizz_condition(number_to_check, fizz_num):
output = False

return output

def keyword_check_fizzbuzz(number_to_check: int, fizz_num: int = 3, buzz_num: int = 5, fizz_con


""" This function checks if a number is fizz but not buzz, i.e. number is a multiple of 3 b
Paramaters
----------
number_to_check : int
input integer to check for fizz
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------

23
bool
True if number passes fizz and buzz check.
"""
if fizz_condition(number_to_check, fizz_num) and buzz_condition(number_to_check, buzz_num):
output = True
else:
output = False

return output

def keyword_fizzbuzz(list_to_mutate: list, fizz_num: int = 3, buzz_num: int = 5, fizz_condition


""" This function takes a list of numbers and mutates it to replace numbers that are multip
Paramaters
----------
list_to_mutate : list
input list of numbers to mutate
fizz_num : int
input integer to use for fizz check
buzz_num : int
input integer to use for buzz check

Returns
-------
None
This function does not return anything, but mutates the list_to_mutate in place.
"""
for i in range(len(list_to_mutate)):
if keyword_check_fizzbuzz(list_to_mutate[i], fizz_num=fizz_num, buzz_num=buzz_num, fizz
list_to_mutate[i] = fizz_word + buzz_word
elif keyword_check_fizz(list_to_mutate[i], fizz_num=fizz_num, buzz_num=buzz_num, fizz_c
list_to_mutate[i] = fizz_word
elif keyword_check_buzz(list_to_mutate[i], fizz_num=fizz_num, buzz_num=buzz_num, fizz_c
list_to_mutate[i] = buzz_word

list_to_mutate = [i for i in range(1,51)] # Create a list to mutate


keyword_fizzbuzz(list_to_mutate, fizz_num=17, buzz_num=16, fizz_word='hello', buzz_word='world'
print(list_to_mutate)

#output ['helloworld', 'world', 'helloworld', 'world', 'world', 'helloworld', 'world', 'world',

2.1 That’s all for functions for now


There are many advanced topics to functions which make them even more versatile. However for
now this is all you should need to wite robust and useful functions to make reuse of code that much
easier.

24
If you want to test out writing any more of your own functions there is a code cell below.
[ ]:

2.2 Next Section


04-IOAndContext

25

You might also like