# Basic command-line Python calculator

I made this basic Python calculator. It just does addition, subtraction, division, and multlipication.

I feel like the code is a mess, but it does what I want it to, and I feel like it does it effectively.

import operator

def calculate (first_number, operation_type, second_number):
if operation_type == 'a':
if operation_type == 's':
if operation_type == 'm':
if operation_type == 'd':

while True:
while True:
try:
first_number = int(input("Enter first number: "))
break
except ValueError:
print ("Enter a number!\n")
pass

while True:
operation_type = str(input("\nA - add\nS - subtract\nM - multiply\nD - divide\nEnter operation type: "))
operation_type = operation_type.lower()

if operation_type in {'a', 'm', 'd', 's'}:
break
else:
print ("Invalid operation type!\n")
pass

while True:
try:
second_number = int(input("\nEnter second number: "))
break
except ValueError:
print ("Enter a number!\n")
pass

print (calculate (first_number, operation_type, second_number))

run_again = str(input("Run again? Type 'y' to continue, or q to quit: "))
if run_again.lower() == 'y':
pass
if run_again.lower() == 'q':
break
elif run_again.lower() != 'y' and run_again.lower() != 'q':
print ("Invalid entry")
break


You imported operator, but did not take advantage of it. That's unfortunate, because the module contains exactly what a simple calculator program needs: binary functions for arithmetic. Your calculate() function could reduce to this:

import operator

OPERATIONS = {
's': operator.sub,
'm': operator.mul,
'd': operator.truediv,
}

def calculate(a, op, b):
return OPERATIONS[op](a, b)


If code is repetitive, functions usually help. Most of your code is repetitive stuff to get user input. When you see that kind of repetition, your first instinct should be to extract out the common parts into a function. Collecting user input usually involves three things: (1) a prompt telling the user what to enter, (2) code to convert the input string into the desired type of value, and (3) code to validate that value. The "code" to convert and validate can often take the form of built-in functions/methods (for example, int, float, or str.lower) or, when needed, short functions or lambdas that you define. Here's one way to implement a user-input function in a fairly generalized way applicable to many programs:

def get_input(prompt, convert, validate):
invalid_msg = 'Invalid input.'
while True:
reply = input(prompt + ': ')
try:
if validate(val):
return val
else:
print(invalid_msg)
except Exception as e:
print(invalid_msg)


Put all code in functions. Even in small programs. Your calculator code becomes fairly simple once you have a user-input function to handle the grubby details.

def main():
op_prompt = '\nA - add\nS - subtract\nM - multiply\nD - divide\nEnter operation'
op_is_valid = lambda x: x in OPERATIONS
yn_is_valid = lambda x: x in 'yn'
always_valid = lambda x: True
while True:
a = get_input('Enter first number', int, always_valid)
op = get_input(op_prompt, str.lower, op_is_valid)
b = get_input('Enter second number', int, always_valid)
result = calculate(a, op, b)
print(result)
if get_input('Run again [y/n]', str.lower, yn_is_valid) == 'n':
break

if __name__ == '__main__':
main()


Next steps: better user experience. (1) This code above does not handle the division-by-zero scenario, but you could easily make that adjustment. (2) Support floats: no good reason not to. (3) Consider simplifying the burden on the user: instead of forcing them to engage in four discrete dialogues with the computer (first number? operator? second number? continue?), which becomes tedious very rapidly, just let them type a normal arithmetic expression (delimited by spaces) and interpret a blank entry as the signal for quit. Here's what a session might look like.

Simple calculator:
12 + 13
=> 25
5 - 3
=> 2
3 / 0
=> Error: division by zero
9 * 9
=> 81

Goodbye.