03 Functions
03 Functions
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
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)
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:
""" 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.
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.
return 1, 2, 'boo'
b) A function has a single exit point Another counter example showing valid Python that
you shouldnt do.
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'
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.
7
input_list.append(input_item)
# Update list length
global list_length
list_length +=1
list_in = [1,2,3]
list_length = 3
append_item_to_list(list_in, 4)
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
8
Hint 2, second part of check_fizz
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
if number_to_check % 5 == 0:
output = False
return output
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
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
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
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
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␣
---------------------------------------------------------------------------
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
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.
15
It is likely you will want to use all of these in your answer.
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.
"""
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.
"""
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.3 Answers
Solution to keyword_fizzbuzz
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
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
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
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
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
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
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
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
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
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
24
If you want to test out writing any more of your own functions there is a code cell below.
[ ]:
25