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()
-
\$\begingroup\$ Welcome to Code Review! Your post looks fine, hope you get some good answers! \$\endgroup\$ferada– ferada2021年08月11日 15:13:25 +00:00Commented Aug 11, 2021 at 15:13
1 Answer 1
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()