Can this calculator be made shorter and more compact?

57 Views Asked by At

Is there a way to make my calculator function simpler and easier to read?
I tried looping it, but all in all it looks too complicated somehow.

def calculator():
    while True:
        calc = input("Enter 'add', 'sub', 'mul' or 'div': ")

        if calc == 'add':
            first = float(input("First number: "))
            second = float(input("Second number: "))
            result = first + second
            print("Result:", result)
            break
        elif calc == 'sub':
            first = float(input("First number: "))
            second = float(input("Second number: "))
            result = first - second
            print("Result: ", result)
            break
        elif calc == 'mul':
            first = float(input("First number: "))
            second = float(input("Second number: "))
            result = first * second
            print("Result: ", result)
            break
        elif calc == 'div':
            first = float(input("First number: "))
            second = float(input("Second number: "))
            if second != 0:
                result = first / second
                print("Result: ", result)
                break
            else:
                print("It's not possible to divide by zero. Please try again.")
        else:
            print("Incorrect variables. Please try again.")

if  __name__=="__main__":
    calculator()
2

There are 2 best solutions below

0
Maurice Meyer On

You could make use of operator:

import operator


def calculator():
    while True:
        calc = input("Enter 'add', 'sub', 'mul' or 'div': ")

        # rename div to truediv in order to use the function from operator
        calc = 'truediv' if calc == 'div' else calc
        first = float(input("First number: "))
        second = float(input("Second number: "))

        # function reference from operator, None as default if not matching function found!
        func = getattr(operator, calc, None)

        if not func:
            print("No math operator found!")
            continue

        if calc == 'div' and second == 0:
            print("It's not possible to divide by zero. Please try again.")
            continue

        result = func(first, second)
        print("Result:", result)


if __name__ == "__main__":
    calculator()

Out:

Enter 'add', 'sub', 'mul' or 'div': div
First number: 6
Second number: 2
Result: 3.0
Enter 'add', 'sub', 'mul' or 'div': add
First number: 4
Second number: 13
Result: 17.0
0
SIGHUP On

You can construct a dictionary that acts as a mapping between user input and the associated operation to make life easier.

The while loop will terminate when input is empty.

With judicious use of exception handlers you only need one if statement as follows:

import operator

FMAP = {
    "add": operator.add,
    "sub": operator.sub,
    "mul": operator.mul,
    "div": operator.truediv,
    #"pow": operator.pow,
    #"mod": operator.mod,
    #"fdv": operator.floordiv,
}

def options():
    first, *middle, last = FMAP.keys()
    _options = f"Enter '{first}'"
    for key in middle:
        _options += f", '{key}'"
    return _options + f" or '{last}': "


while calc := input(options()):
    if func := FMAP.get(calc):
        try:
            x = float(input("Enter value for x: "))
            y = float(input("Enter value for y: "))
            print("Result:", func(x, y))
        except (ValueError, ZeroDivisionError) as e:
            print(e)
    else:
        print("Unrecognised operation")

Note how, by using a dictionary to "drive" the code, one can easily add more functionality simply by editing the FMAP dictionary.