3
\$\begingroup\$

Below is a simple calculator program in which I'm using break statements to control the logic. I was wondering if this is overkill on the break statements or is it OK.

while True:
 try:
 print("Choose operation(+ | - | * | / | Enter 'e' to exit)")
 op=input()
 if op!="+" and op!="-" and op!="*" and op!="/" and op!="e":
 print("Invalid input, you must choose an option from the menu.")
 break
 elif op=="e":
 break
 else:
 print(">")
 val1=float(input(val1))
 print(">")
 val2=float(input(val2))
 if op=="+":
 print("= ", val1+val2)
 elif op=="-":
 print("= ", val1-val2) 
 elif op=="*":
 print("= ", val1*val2)
 else:
 print("= ", val1/val2) 
 except ValueError: 
 print("Input must be numerical.") 
 break 
 except ZeroDivisionError:
 print("Dividing by zero is undefined.")
 break
exit()
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Aug 11, 2021 at 12:40
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code Review! Your post looks fine, hope you get some good answers! \$\endgroup\$ Commented Aug 11, 2021 at 15:13

1 Answer 1

2
\$\begingroup\$

Choosing an Operation

You can use a dictionary, rather than if/elif/else statements to choose operations more cleanly:

from operator import add, sub, mul, truediv
OPERATIONS = {
 '+': add,
 '-': sub,
 '*': mul,
 '/': truediv
}
# if an operation is present
print(OPERATIONS['+'](1, 2))
3
# otherwise
print(OPERATIONS['%'](1, 2))
KeyError

Now, you can clean up your if statements, and get rid of most of your if op == checks:

op = input("Choose operation(+ | - | * | / | Enter 'e' to exit)\n").strip()
if op == 'e':
 print('Exiting')
 exit()
try:
 operation = OPERATIONS[op]
except KeyError:
 print(f"{op} was an invalid choice")
 break
~snip~
# This is how you'd use that operation, since it is a function
try:
 print(operation(val1, val2))
except ZeroDivisionError:
 print("Can't divide by zero!")

Choosing val1 and val2

I think you made a typo by mistake and the argument to input was supposed to be input('val1') and input('val2'). Either way, I think it might be a bit cleaner to add a function here. This makes it easier to wrap up the possible ValueErrors that could come from generating your values on bad input:

def get_input_values():
 """
 Parse numerical input into floats for calculator operations
 """
 values = []
 for i in range(2):
 print('>')
 # this gives some visual space for the user to break up
 # the prompt from the actual input
 val = float(input(f'val{i}: ')
 values.append(val)
 return value
# now you can do a try/except wrapping this function
# and unpack the result
try:
 val1, val2 = get_input_values()
except ValueError as e:
 print(e)
 exit()

You could even extend this to N values if you wanted to:

def get_input_values(N=2):
 ~snip~
 for i in range(N):
 # rest of function
try:
 values = get_input_values(5)
except ValueError as e:
 ~snip~

Adding a main function and __name__ guard

This will help wrap your code up into a single function that can be called/looped/etc. It's cleaner and, for larger programs, makes it easier to find what runs the code. Also, an if __name__ == "__main__" guard allows you to import items from this code without it executing:

# OPERATIONS still lives in global scope here
OPERATIONS = {
 '+': add,
 '-': sub,
 '*': mul,
 '/': truediv
}
def main():
 op = input("Choose operation(+ | - | * | / | Enter 'e' to exit)\n").strip()
 
 if op == 'e':
 print('Exiting')
 exit()
 try:
 operation = OPERATIONS[op]
 except KeyError:
 print(f"{op} was an invalid choice")
 break
 try:
 val1, val2 = get_input_values()
 except ValueError as e:
 print(e)
 exit()
 try:
 result = operation(val1, val2)
 except ZeroDivisionError:
 print("Can't divide by zero!")
 exit()
 else:
 print(result)
if __name__ == "__main__":
 # you can move your loop down here now
 while True:
 main()
 
 
answered Aug 11, 2021 at 13:17
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.