Introduction to Python Programming - Session 4 Catchup
This article was for Hacksoc Nottingham, while I was the 2015-2016 General Secretary.
Repeating Input Less Intrusively
Previously, we would ask the user whether they want to exit, or not, and then would carry on the program. However, this is a bit intrusive, and can get aggravating if they wish to enter more numbers, as they will have to break their workflow and enter "no". Instead, we'll update the program so that we can instead enter -1
to exit.
def get_number_from_user(prompt_string):
number = raw_input(prompt_string)
number = float(number)
return number
def get_string_from_user(prompt_string):
string = raw_input(prompt_string)
string = str(string)
return string
def get_result(number1, number2, operation):
if(operation == "minus"):
result = number1 - number2
elif(operation == "plus"):
result = number1 + number2
elif(operation == "divide"):
result = number1 / number2
elif(operation == "multiply"):
result = number1 * number2
return result
def get_operation_from_user(number2):
operation = ""
isInvalidInput = True
while isInvalidInput:
operation = get_string_from_user("Please enter operation 'plus' 'minus' 'divide' 'multiply': ")
if(operation == "minus"):
isInvalidInput = False
elif(operation == "plus"):
isInvalidInput = False
elif(operation == "divide"):
if(number2 == 0):
isZero = True
while isZero:
print "Hey! You can't divide by zero, dummy"
number2 = get_number_from_user("Please enter the second number: ")
if number2 != 0:
isZero = False
isInvalidInput = False
elif(operation == "multiply"):
isInvalidInput = False
else:
print "Woops, you didn't give me a valid operation ('plus' 'minus' 'divide' 'multiply')"
return operation, number2
wantMoreCalculations = True
while wantMoreCalculations:
number1 = get_number_from_user("Please enter the first number (enter -1 to exit): ")
if(number1 == -1):
wantMoreCalculations = False
break
number2 = get_number_from_user("Please enter the second number: ")
operation, number2 = get_operation_from_user(number2)
result = get_result(number1, number2, operation)
print number1, operation, number2, "equals", result
Exercises:
- Can you think why we used the
break
keyword here, instead of just settingwantMoreCalculations
toFalse
? - After each new entry, create a blank line of input to make it more obvious where one case begins, and another ends. Such as:
Please enter the first number (enter -1 to exit): 123
Please enter the second number: 12
Please enter operation 'plus' 'minus' 'divide' 'multiply': plus
123.0 plus 12.0 equals 135.0
Please enter the first number (enter -1 to exit):
A More Friendly Program
In the following sections, we're going to adapt the program to use a menu system, so the user can do multiple things in each program run, such as view the history of previously run calculations.
def get_number_from_user(prompt_string):
number = raw_input(prompt_string)
number = float(number)
return number
def get_string_from_user(prompt_string):
string = raw_input(prompt_string)
string = str(string)
return string
def get_result(number1, number2, operation):
if(operation == "minus"):
result = number1 - number2
elif(operation == "plus"):
result = number1 + number2
elif(operation == "divide"):
result = number1 / number2
elif(operation == "multiply"):
result = number1 * number2
return result
def get_operation_from_user(number2):
operation = ""
isInvalidInput = True
while isInvalidInput:
operation = get_string_from_user("Please enter operation 'plus' 'minus' 'divide' 'multiply': ")
if(operation == "minus"):
isInvalidInput = False
# result = number1 - number2
elif(operation == "plus"):
isInvalidInput = False
# result = number1 + number2
elif(operation == "divide"):
if(number2 == 0):
isZero = True
while isZero:
print "Hey! You can't divide by zero, dummy"
number2 = get_number_from_user("Please enter the second number: ")
if number2 != 0:
isZero = False
isInvalidInput = False
# result = number1 / number2
elif(operation == "multiply"):
isInvalidInput = False
# result = number1 * number2
else:
print "Woops, you didn't give me a valid operation ('plus' 'minus' 'divide' 'multiply')"
return operation, number2
def perform_calculation():
number1 = get_number_from_user("Please enter the first number (enter -1 to exit): ")
if(number1 == -1):
return False
number2 = get_number_from_user("Please enter the second number: ")
operation, number2 = get_operation_from_user(number2)
result = get_result(number1, number2, operation)
print number1, operation, number2, "equals", result
return True
print "Hello, welcome to the awesome calculator program"
print "These are your options:"
print " 1. Perform calculations"
print " 0. Exit program"
menu_option = get_number_from_user("Please enter your menu option: ")
if(menu_option == 1):
wantMoreCalculations = True
while wantMoreCalculations:
wantMoreCalculations = perform_calculation()
elif(menu_option == 0):
pass
else:
print "Woops, you dun goofed. Please enter 0 or 1 as valid input"
You'll notice that we've removed the main loop of the program, and instead replaced it with a menu system, which for now only provides us with the ability to run calculations or exit.
We move our main loop from the previous version into the perform_calculation
function, which allows us to then return a boolean value as to whether the user wishes to keep processing or not. This then sets the value of the while
loop in the menu.
Exercises:
- What happens if we get rid of the
pass
? And what if there is noelif(menu_option == 0):
case?
A Proper Menu System
In our previous example, we would exit the program if we entered -1
inside perform_calculation
- which isn't useful because when we extend the menu, we can't do more than one thing at once, especially if we enter a wrong menu item.
def get_number_from_user(prompt_string):
number = raw_input(prompt_string)
number = float(number)
return number
def get_string_from_user(prompt_string):
string = raw_input(prompt_string)
string = str(string)
return string
def get_result(number1, number2, operation):
if(operation == "minus"):
result = number1 - number2
elif(operation == "plus"):
result = number1 + number2
elif(operation == "divide"):
result = number1 / number2
elif(operation == "multiply"):
result = number1 * number2
return result
def get_operation_from_user(number2):
operation = ""
isInvalidInput = True
while isInvalidInput:
operation = get_string_from_user("Please enter operation 'plus' 'minus' 'divide' 'multiply': ")
if(operation == "minus"):
isInvalidInput = False
# result = number1 - number2
elif(operation == "plus"):
isInvalidInput = False
# result = number1 + number2
elif(operation == "divide"):
if(number2 == 0):
isZero = True
while isZero:
print "Hey! You can't divide by zero, dummy"
number2 = get_number_from_user("Please enter the second number: ")
if number2 != 0:
isZero = False
isInvalidInput = False
# result = number1 / number2
elif(operation == "multiply"):
isInvalidInput = False
# result = number1 * number2
else:
print "Woops, you didn't give me a valid operation ('plus' 'minus' 'divide' 'multiply')"
return operation, number2
def perform_calculation():
number1 = get_number_from_user("Please enter the first number (enter -1 to exit): ")
if(number1 == -1):
return False
number2 = get_number_from_user("Please enter the second number: ")
operation, number2 = get_operation_from_user(number2)
result = get_result(number1, number2, operation)
print number1, operation, number2, "equals", result
return True
stayInMenu = True
while stayInMenu:
isInvalidInput = True
while isInvalidInput:
print "Hello, welcome to the awesome calculator program"
print "These are your options:"
print " 1. Perform calculations"
print " 0. Exit program"
menu_option = get_number_from_user("Please enter your menu option: ")
if menu_option == 1 or menu_option == 0:
isInvalidInput = False
else:
print "Woops, you dun goofed. Please enter 0 or 1 as valid input"
if(menu_option == 1):
wantMoreCalculations = True
while wantMoreCalculations:
wantMoreCalculations = perform_calculation()
elif(menu_option == 0):
stayInMenu = False
Therefore we add a loop around our menu code, and until we get valid input, as we've done in previous versions of the code.
Global Variables and Scope
Before we carry on, we need to talk about scope (scope: the visibility of variables).
We previously mentioned that function parameters are only valid inside the function, and as such, won't get reflected in the main program. This is an example of scoping - the function has its own copy of the variable, at its scope, and will only update that, instead of the instance in the main program.
This can be demonstrated by the following code:
a = 0
def inc_global_a():
# Because we modify the global variable we
# need to say this is the global version
global a
a = a + 1
def set_a_to_zero():
# No global keyword means this variable is local
a = 0
def print_a():
# No editing means we can just reference 'a'
print "The global value of 'a' is: ", a
def print_parameter_a(a):
# because of scoping rules, Python 'sees' the parameter
# instead of the global
print "The value of the parameter 'a' is: ", a
print ""
print "The original value of a"
print_a()
print_parameter_a(10)
inc_global_a()
print ""
print "After incrementing the global variable"
print_a()
print_parameter_a(10)
set_a_to_zero()
print ""
print "After zeroing the local variable"
print_a()
print_parameter_a(10)
Storing Calculator Memory
Scoping rules are very important, as we will see in this section, so we are able to access a global variable.
In the following example, we provide the ability to recall the most recent calculation.
# our global last calculation variable
lastCalculation = -1
def get_number_from_user(prompt_string):
number = raw_input(prompt_string)
number = float(number)
return number
def get_string_from_user(prompt_string):
string = raw_input(prompt_string)
string = str(string)
return string
def get_result(number1, number2, operation):
if(operation == "minus"):
result = number1 - number2
elif(operation == "plus"):
result = number1 + number2
elif(operation == "divide"):
result = number1 / number2
elif(operation == "multiply"):
result = number1 * number2
return result
def get_operation_from_user(number2):
operation = ""
isInvalidInput = True
while isInvalidInput:
operation = get_string_from_user("Please enter operation 'plus' 'minus' 'divide' 'multiply': ")
if(operation == "minus"):
isInvalidInput = False
# result = number1 - number2
elif(operation == "plus"):
isInvalidInput = False
# result = number1 + number2
elif(operation == "divide"):
if(number2 == 0):
isZero = True
while isZero:
print "Hey! You can't divide by zero, dummy"
number2 = get_number_from_user("Please enter the second number: ")
if number2 != 0:
isZero = False
isInvalidInput = False
# result = number1 / number2
elif(operation == "multiply"):
isInvalidInput = False
# result = number1 * number2
else:
print "Woops, you didn't give me a valid operation ('plus' 'minus' 'divide' 'multiply')"
return operation, number2
def perform_calculation():
number1 = get_number_from_user("Please enter the first number (enter -1 to exit): ")
if(number1 == -1):
return False
number2 = get_number_from_user("Please enter the second number: ")
operation, number2 = get_operation_from_user(number2)
result = get_result(number1, number2, operation)
global lastCalculation
lastCalculation = result
print number1, operation, number2, "equals", result
return True
stayInMenu = True
while stayInMenu:
isInvalidInput = True
while isInvalidInput:
print "Hello, welcome to the awesome calculator program"
print "These are your options:"
print " 1. Perform calculations"
print " 2. Print last calculation"
print " 0. Exit program"
menu_option = get_number_from_user("Please enter your menu option: ")
if menu_option == 2 or menu_option == 1 or menu_option == 0:
isInvalidInput = False
else:
print "Woops, you dun goofed. Please enter 0 or 1 as valid input"
if(menu_option == 1):
wantMoreCalculations = True
while wantMoreCalculations:
wantMoreCalculations = perform_calculation()
elif(menu_option == 2):
print "Your last calculation was ", lastCalculation
elif(menu_option == 0):
stayInMenu = False
Following the previous example, we need to tell Python that we want to access the global variable lastCalculation
, so we then are able to bring it into scope, and assign to it.
Storing Multiple Calculations
Storing only one calculation is a bit annoying. Instead, we want to store all our history - and to do this, we need to take advantage of lists (lists (also known as arrays): a sequence of particular items, in a given order). Lists are a great way of storing multiple values, without having to have a variable per item - which when we're running i.e. a large web server, we'll never know how much data we're going to be given.
NOTE: In our next session, we are going to play around with lists in much more depth; if you don't fully understand them for now, don't worry!
# our global last calculation variable
# create a new empty list
lastCalculation = []
def get_number_from_user(prompt_string):
number = raw_input(prompt_string)
number = float(number)
return number
def get_string_from_user(prompt_string):
string = raw_input(prompt_string)
string = str(string)
return string
def get_result(number1, number2, operation):
if(operation == "minus"):
result = number1 - number2
elif(operation == "plus"):
result = number1 + number2
elif(operation == "divide"):
result = number1 / number2
elif(operation == "multiply"):
result = number1 * number2
return result
def get_operation_from_user(number2):
operation = ""
isInvalidInput = True
while isInvalidInput:
operation = get_string_from_user("Please enter operation 'plus' 'minus' 'divide' 'multiply': ")
if(operation == "minus"):
isInvalidInput = False
# result = number1 - number2
elif(operation == "plus"):
isInvalidInput = False
# result = number1 + number2
elif(operation == "divide"):
if(number2 == 0):
isZero = True
while isZero:
print "Hey! You can't divide by zero, dummy"
number2 = get_number_from_user("Please enter the second number: ")
if number2 != 0:
isZero = False
isInvalidInput = False
# result = number1 / number2
elif(operation == "multiply"):
isInvalidInput = False
# result = number1 * number2
else:
print "Woops, you didn't give me a valid operation ('plus' 'minus' 'divide' 'multiply')"
return operation, number2
def perform_calculation():
number1 = get_number_from_user("Please enter the first number (enter -1 to exit): ")
if(number1 == -1):
return False
number2 = get_number_from_user("Please enter the second number: ")
operation, number2 = get_operation_from_user(number2)
result = get_result(number1, number2, operation)
global lastCalculation
lastCalculation.append(result)
print number1, operation, number2, "equals", result
return True
stayInMenu = True
while stayInMenu:
isInvalidInput = True
while isInvalidInput:
print "Hello, welcome to the awesome calculator program"
print "These are your options:"
print " 1. Perform calculations"
print " 2. Print last calculation"
print " 0. Exit program"
menu_option = get_number_from_user("Please enter your menu option: ")
if menu_option == 2 or menu_option == 1 or menu_option == 0:
isInvalidInput = False
else:
print "Woops, you dun goofed. Please enter 0 or 1 as valid input"
if(menu_option == 1):
wantMoreCalculations = True
while wantMoreCalculations:
wantMoreCalculations = perform_calculation()
elif(menu_option == 2):
print "Your last calculations were: ", lastCalculation
elif(menu_option == 0):
stayInMenu = False
We create a new, empty list, to store our calculations in, and then every time we have a new result, we append
it to the end of the list.
Storing More Useful Data
We've previously only stored our previous calculations, but we can do better than that; we can store the actual values that created a given result.
To do this, we can't put every value inside the array, because we would then have no structure for the values. Luckily, there is a type called a tuple (tuple: a data structure consisting of multiple parts) which allows us to store numerous pieces of data in the same area. This is really useful because we'll be able to store our number1
, number2
and operation
together, inside the array, as so:
array(
tuple(
number1 = 123,
number2 = 12,
operation = divide
)
,
tuple(
number1 = 9000,
number2 = 1,
operation = plus
)
,
...
)
NOTE: In our next session, we are going to play around with tuples and iterating through lists in much more depth; if you don't fully understand them for now, don't worry!
# our global last calculation variable
lastCalculations = []
def get_number_from_user(prompt_string):
number = raw_input(prompt_string)
number = float(number)
return number
def get_string_from_user(prompt_string):
string = raw_input(prompt_string)
string = str(string)
return string
def get_result(number1, number2, operation):
if(operation == "minus"):
result = number1 - number2
elif(operation == "plus"):
result = number1 + number2
elif(operation == "divide"):
result = number1 / number2
elif(operation == "multiply"):
result = number1 * number2
return result
def get_operation_from_user(number2):
operation = ""
isInvalidInput = True
while isInvalidInput:
operation = get_string_from_user("Please enter operation 'plus' 'minus' 'divide' 'multiply': ")
if(operation == "minus"):
isInvalidInput = False
# result = number1 - number2
elif(operation == "plus"):
isInvalidInput = False
# result = number1 + number2
elif(operation == "divide"):
if(number2 == 0):
isZero = True
while isZero:
print "Hey! You can't divide by zero, dummy"
number2 = get_number_from_user("Please enter the second number: ")
if number2 != 0:
isZero = False
isInvalidInput = False
# result = number1 / number2
elif(operation == "multiply"):
isInvalidInput = False
# result = number1 * number2
else:
print "Woops, you didn't give me a valid operation ('plus' 'minus' 'divide' 'multiply')"
return operation, number2
def perform_calculation():
number1 = get_number_from_user("Please enter the first number (enter -1 to exit): ")
if(number1 == -1):
return False
number2 = get_number_from_user("Please enter the second number: ")
operation, number2 = get_operation_from_user(number2)
global lastCalculations
lastCalculation = (number1, number2, operation)
lastCalculations.append(lastCalculation)
output_result(number1, number2, operation)
return True
def output_result(number1, number2, operation):
# TODO: what should go here?!
print "TODO: This function needs to be finished!"
stayInMenu = True
while stayInMenu:
isInvalidInput = True
while isInvalidInput:
print "Hello, welcome to the awesome calculator program"
print "These are your options:"
print " 1. Perform calculations"
print " 2. Print last calculation"
print " 0. Exit program"
menu_option = get_number_from_user("Please enter your menu option: ")
if menu_option == 2 or menu_option == 1 or menu_option == 0:
isInvalidInput = False
else:
print "Woops, you dun goofed. Please enter 0 or 1 as valid input"
if(menu_option == 1):
wantMoreCalculations = True
while wantMoreCalculations:
wantMoreCalculations = perform_calculation()
elif(menu_option == 2):
print "Your last calculations were:"
for calculation in lastCalculations:
number1 = calculation[0]
number2 = calculation[1]
operation = calculation[2]
output_result(number1, number2, operation)
elif(menu_option == 0):
stayInMenu = False
We have a couple of key changes here:
- Create a new function called
output_result
to print out the result, given the variables required. However, you will need to implement it yourself! - We create a local variable of type tuple (denoted by the
(number1,...)
syntax), to temporarily store our data, and then append it onto ourlastCalculations
list - Finally, we actually output the value of the list. To do this, we iterate (iterate: repeat through a set of variable(s)) through our
lastCalculations
list, which loops through each tuple inside and prints out the values. NOTE: we will be covering this in more depth in our next session - don't worry if you don't understand it right now.
Exercises:
- Implement the
output_result
function so that it prints out in the format"(number1) (operation) (number2) equals (result)"
- Update the
output_result
function so that it takes in a tuple, opposed to each variable separately