Problem
What do you think about this simple calculator?
while True:
print('Options:')
print('Enter 'a' to add two numbers')
print('Enter 's' to subtract two numbers')
print('Enter 'm' to multiply two numbers')
print('Enter 'd' to divide two numbers')
print('Enter 'q' to quit the program')
response=str(input(':')).lower()
if response=='q':
break
elif response=='a':
while True:
try:
num1=float(input('Enter a number:'))
break
except(TypeError,ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2=float(input('Enter another number:'))
break
except(TypeError,ValueError):
print('*(Input Error) Enter valid number*')
continue
result=num1+num2
print('The answer is '+str(result))
print()
elif response=='s':
while True:
try:
num1=float(input('Enter a number:'))
break
except(TypeError,ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2=float(input('Enter another number:'))
break
except(TypeError,ValueError):
print('*(Input Error) Enter valid number*')
continue
result=num1-num2
print('The answer is '+str(result))
print()
elif response=='m':
while True:
try:
num1=float(input('Enter a number:'))
break
except(TypeError,ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2=float(input('Enter another number:'))
break
except(TypeError,ValueError):
print('*(Input Error) Enter valid number*')
continue
result=num1*num2
print('The answer is '+str(result))
print()
elif response=='d':
while True:
try:
num1=float(input('Enter a number:'))
break
except(TypeError,ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2=float(input('Enter another number:'))
break
except(TypeError,ValueError):
print('*(Input Error) Enter valid number*')
continue
result=num1/num2
print('The answer is '+str(result))
print()
else:
print('*Unknown input*')
continue
Solution
Welcome to the world of beginner Python programming, and programming in general! Python is a nice language to learn and start out with!
Allow me to give you some tips and pointers, with the hope that you will be able to learn a little from them.
Also, allow me to apologize in advance for this massive wall of text. I may have gone a little bit overboard in my review and analysis, but I wanted to make sure you would understand my revisions and some of the code I’ve added, in the event you are unfamiliar with the functionality I implement and use in the reviewed and revised code.
Add white space for readability, and obey PEP8 rules for whitespace around assignment and equality operators
Python is extremely indentation-based. This means an indent usually indicates a code block that needs executed underneath of another one (such as your if statements have, etc).
However, Python also benefits from having white space added at logical locations for readability. I usually define these locations as between loops and other sections of code, between functional statements (addition, subtraction, etc.) and output, between the end of an if statement and the beginning of its elif
or else
blocks, after the end of an entire if
block, etc.
There is also a rule for Python code style, called the PEP8 which dictates whitespace around assignment statements, equality operators (such as ==
), and also arithmetic operators (+
, -
, *
, /
, and others), stating that a space is necessary around them.
This is your code with the whitespace per my guidelines and the PEP8 guidelines. My further reviews from here will be using this as a base.
while True:
print('Options:')
print('Enter 'a' to add two numbers')
print('Enter 's' to subtract two numbers')
print('Enter 'm' to multiply two numbers')
print('Enter 'd' to divide two numbers')
print('Enter 'q' to quit the program')
response = str(input(':')).lower()
if response == 'q':
break
elif response == 'a':
while True:
try:
num1 = float(input('Enter a number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2 = float(input('Enter another number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
result = num1 + num2
print('The answer is ' + str(result))
print()
elif response == 's':
while True:
try:
num1 = float(input('Enter a number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2 = float(input('Enter another number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
result = num1 - num2
print('The answer is ' + str(result))
print()
elif response == 'm':
while True:
try:
num1 = float(input('Enter a number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2 = float(input('Enter another number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
result = num1 * num2
print('The answer is ' + str(result))
print()
elif response == 'd':
while True:
try:
num1 = float(input('Enter a number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2 = float(input('Enter another number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
result = num1 / num2
print('The answer is ' + str(result))
print()
else:
print('*Unknown input*')
continue
Move non-quit responses to separate “if” block, so we can do some tasks without repeating code.
One of the major guidelines of programming is that if you are doing something that requires you to copy and paste code in all the time to do the same thing, chances are there’s a better implementation.
You currently do this in every single block of code under each conditional check for the response entered, except for quitting and invalid responses:
while True:
try:
num1 = float(input('Enter a number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2 = float(input('Enter another number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
We can easily move this to outside the if
block, if we separate the a
, s
, m
, and d
response checks to somewhere else, so we don’t have to repeat all the code, which actually will save you a lot of lines of code. This is the new set of if
/elif
statements, with the ‘quit’ response checked before we even begin to look at other responses, and the deletion of the “else” clause that you had in there:
if response == 'q':
break
while True:
try:
num1 = float(input('Enter a number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2 = float(input('Enter another number:'))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
if response == 'a':
result = num1 + num2
elif response == 's':
result = num1 - num2
elif response == 'm':
result = num1 * num2
elif response == 'd':
result = num1 / num2
Note that while I drop the “Unknown Input” check (that else
statement at the end), we’re going to add it back in elsewhere in the code in my next recommendation.
Move “Invalid Input” check to second thing checked in the if
/elif
block for “Quit” checking
This recommendation builds from the previous recommendation above this one; it should not be implemented without the previous recommendation, as it builds off of the previous recommendation
You’ll note that I removed the else
block that handled “Unknown Input” captures in my earlier recommendation. That’s because we can implement it in a better place, and earlier on in the code, and handle things as a “Check if input is valid before anything else” approach, which is what we’ll cover in this section.
Basically, we don’t need to put the “Invalid Input” check at the bottom. Instead, we can check it at the beginning!
This is the code that will do that:
if response == 'q':
break
elif response not in 'asmd':
print('*Unknown input*')
continue
Because you’re a beginner, let me break down the elif
here. Basically this says “Is the value of response
contained within this string of valid response characters?”, and if it is not, then it will print the “Unknown Input” error, and continue on to the next iteration of the loop – skipping all other code below it.
Unnecessary continue
statement at end of loop
In your original code, you have the continue
statement at the end of the code underneath the while
loop. This is unnecessary – when the end of the code under the loop is reached, it will automatically continue on to the next iteration, and you don’t need the continue
statement here.
You can just remove that continue
statement.
Improper checking of ‘length’ of response
This builds off my two earlier recommendations for changing your if
and elif
blocks for “Quit” and “Invalid Response” to their own block at the beginning, and then have a separate if
/elif
block for response checking only.
So, in my recommendations, I don’t properly check the length of the response provided. That means I potentially introduce breakage where it’s listed as “unknown input” So, let’s do that as part of “Invalid Input” checks, by checking if the length of the response is greater than one, or if it’s not in the ‘valid responses’ we defined. The code below does that.
if response == 'q':
break
elif len(response) > 1 or response not in 'asmd':
print('*Unknown input*')
continue
Make Output and Options Prompt a little cleaner
This is more or less up to each programmer, but I believe that the output and prompts you use are a little… cluttered, and harder to read. I also believe input could be better handled in terms of providing users with the prompt.
Let’s start with the options prompt first. We can reorganize and revise these to make output a little nicer, and grab the option in a nicer way than just a colon and a prompt line:
print('Enter 'a' to add two numbers')
print('Enter 's' to subtract two numbers')
print('Enter 'm' to multiply two numbers')
print('Enter 'd' to divide two numbers')
print('Enter 'q' to quit the program')
response = str(input('Select an option: ')).lower()
Note that we got rid of that first print("Options:")
item. You can add it back in if you want.
Next, let’s work on the prompts for the two numbers being worked with, and the output. I think it would benefit from some line breaks to sort of ‘separate up’ the content to make it a little more readable.
I’d like to introduce you to an escaped character sequence: n
. In a string, n
is interpreted as a line break, which generates a blank line in the usages I’m putting in place here when actually displayed to the user.
The following lines should be changed accordingly, to make your output a little nicer:
num1 = float(input('Enter a number:'))
should becomenum1 = float(input('nEnter a number: '))
num2 = float(input('Enter another number:'))
should becomenum2 = float(input('nEnter another number: '))
print('The answer is ' + str(result))
should becomeprint('nThe answer is ' + str(result) + 'n')
print()
should becomeprint('------------------n')
.
This results in program output a little like this, then (using a
, 1
, and 1
):
Enter 'a' to add two numbers
Enter 's' to subtract two numbers
Enter 'm' to multiply two numbers
Enter 'd' to divide two numbers
Enter 'q' to quit the program
Select an option: a
Enter a number: 1
Enter another number: 1
The answer is 2.0
------------------
Enter 'a' to add two numbers
Enter 's' to subtract two numbers
Enter 'm' to multiply two numbers
Enter 'd' to divide two numbers
Enter 'q' to quit the program
Select an option: q
Avoid escaping '
characters, by using "
around the strings containing them
This was originally pointed out in comments by Dex’ter.
In your print statements where you print out the list of available options for the user, you can avoid having to use '
to escape the '
s by using the quotation marks around the entire string instead of apostrophes., like so:
print("Enter 'a' to add two numbers")
print("Enter 's' to subtract two numbers")
print("Enter 'm' to multiply two numbers")
print("Enter 'd' to divide two numbers")
print("Enter 'q' to quit the program")
Complete Code, After Recommendations
This is the code, after all my recommendations from above implemented, in its entirety:
while True:
print("Enter 'a' to add two numbers")
print("Enter 's' to subtract two numbers")
print("Enter 'm' to multiply two numbers")
print("Enter 'd' to divide two numbers")
print("Enter 'q' to quit the program")
response = str(input('Select an option: ')).lower()
if response == 'q':
break
elif len(response) > 1 or response not in 'asmd':
print('*Unknown input*n')
continue
while True:
try:
num1 = float(input('nEnter a number: '))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
while True:
try:
num2 = float(input('nEnter another number: '))
break
except(TypeError, ValueError):
print('*(Input Error) Enter valid number*')
continue
if response == 'a':
result = num1 + num2
elif response == 's':
result = num1 - num2
elif response == 'm':
result = num1 * num2
elif response == 'd':
result = num1 / num2
print('nThe answer is ' + str(result) + 'n')
print('------------------n')