Python calculator including history check with using lists

Viewed 124

I'm a beginner in python so I wanted to create python calculator(with history) by using lists. but when I tried to do it always gives me when I'm checking the history "No past calculations to show"

How to modify this below code for my requirement?

def add(a,b):
return a+b

def subtract(a,b):
return a-b

def multiply (a,b):
return a*b

def divide(a,b):
try:
   return a/b
except Exception as e:
   print(e)

def power(a,b):
   return a**b

def remainder(a,b):
   return a%b

def select_op(choice): 
if (choice == '#'):
    print("Done. Terminating")
    exit()
elif (choice == '$'):
    return main()
elif (choice in ('+','-','*','/','^','%','?')):
    while (True):
        num1s = str(input("Enter first number: "))
        print(num1s)
        if num1s.endswith('$'):
            return main()
        if num1s.endswith('#'):
            print("Done. Terminating")
            exit()   
        try:
            num1 = float(num1s)
            break
        except:
            print("Not a valid number,please enter again")
            continue
    
    while (True):
        num2s = str(input("Enter second number: "))
        print(num2s)
        if num2s.endswith('$'):
            return main()
        if num2s.endswith('#'):
            print("Done. Terminating")
            exit()
        try:  
            num2 = float(num2s)
            break
        except:
            print("Not a valid number,please enter again")
            continue
last_calculation_1=last_calculation_2=last_calculation_3=last_calculation_4=last_calculation_5=last_calculation_6=[]
    if choice == '+':
        result = add(num1, num2)
        msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
        print(msg)
        last_calculation_1.append(msg)
    elif choice == '-':
        result = subtract(num1, num2)
        msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
        print(msg)
        last_calculation_2.append(msg)
    elif choice == '*':
        result = multiply(num1, num2)
        msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
        print(msg)
        last_calculation_3.append(msg)
    elif choice == '/':
        result =  divide(num1, num2)
        msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
        print(msg)
        last_calculation_4.append(msg)
    elif choice == '^':
        result = power(num1, num2)
        msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
        print(msg)
        last_calculation_5.append(msg)
    elif choice == '%':
        result = remainder(num1, num2)
        msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
        print(msg)
        last_calculation_6.append(msg)
    elif choice=='?':
        last_calculation=last_calculation_1+last_calculation_2+last_calculation_3+last_calculation_4+last_calculation_5+last_calculation_6
        # x=[str(i) for i in last_calculation]
        if len(last_calculation) ==0:
            print("No past calculations to show")
        else:
            b="\n".join(last_calculation)
            print(b)
    else:
        print("Something Went Wrong")
else:
    print("Unrecognized operation")
    return main()

def main():   
    while True:
       print("Select operation.")
       print("1.Add      : + ")
       print("2.Subtract : - ")
       print("3.Multiply : * ")
       print("4.Divide   : / ")
       print("5.Power    : ^ ")
       print("6.Remainder: % ")
       print("7.Terminate: # ")
       print("8.Reset    : $ ")
       print("8.History  : ? ")

# take input from the user
    choice = input("Enter choice(+,-,*,/,^,%,#,$,?): ")
    print(choice)
    select_op(choice)

main()    

Task 1: Declare a list to store the previous operations Save the operator, operands and the results as a single string, for each operation after each calculation

Task 2: implement a history() function to handle the operation '?' Display the complete saved list of operations (in the order of execution) using a new command ‘?’ If there are no previous calculations when the history '?' command is used, you can display the following message "No past calculations to show"

2 Answers

One way to do it would be to get rid of all the last_calculation lists and stick to one list for the history called history and initialize it in the main function, then pass it as a parameter into the select_op function and so it can be updated on each subsequent call. Then set the logic to print the contents of the history list if the ? is the input. for example:

def add(a,b):
    return a+b

def subtract(a,b):
    return a-b

def multiply (a,b):
    return a*b

def divide(a,b):
    try:
        return a/b
    except Exception as e:
        print(e)

def power(a,b):
   return a**b

def remainder(a,b):
   return a%b

def select_op(choice, history):
    if (choice == '#'):
        print("Done. Terminating")
        exit()
    elif (choice == '$'):
        return main()
    elif (choice in ('+','-','*','/','^','%')):
        while (True):
            num1s = str(input("Enter first number: "))
            print(num1s)
            if num1s.endswith('$'):
                return main()
            if num1s.endswith('#'):
                print("Done. Terminating")
                exit()
            try:
                num1 = float(num1s)
                break
            except:
                print("Not a valid number,please enter again")
                continue

        while (True):
            num2s = str(input("Enter second number: "))
            print(num2s)
            if num2s.endswith('$'):
                return main()
            if num2s.endswith('#'):
                print("Done. Terminating")
                exit()
            try:
                num2 = float(num2s)
                break
            except:
                print("Not a valid number,please enter again")
                continue
        if choice == '+':
            result = add(num1, num2)
            msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
            print(msg)
            history.append(msg)
        elif choice == '-':
            result = subtract(num1, num2)
            msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
            print(msg)
            history.append(msg)
        elif choice == '*':
            result = multiply(num1, num2)
            msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
            print(msg)
            history.append(msg)
        elif choice == '/':
            result =  divide(num1, num2)
            msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
            print(msg)
            history.append(msg)
        elif choice == '^':
            result = power(num1, num2)
            msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
            print(msg)
            history.append(msg)
        elif choice == '%':
            result = remainder(num1, num2)
            msg="{0} {1} {2} = {3}".format(str(num1), str(choice), str(num2), str(result))
            print(msg)
            history.append(msg)
        else:
            print("Something Went Wrong")
    elif choice=='?':
        if len(history) ==0:
            print("No past calculations to show")
        else:
            b="\n".join(history)
            print(b)
    else:
        print("Unrecognized operation")
        return main()

def main():
    history = []
    while True:
        print("Select operation.")
        print("1.Add      : + ")
        print("2.Subtract : - ")
        print("3.Multiply : * ")
        print("4.Divide   : / ")
        print("5.Power    : ^ ")
        print("6.Remainder: % ")
        print("7.Terminate: # ")
        print("8.Reset    : $ ")
        print("8.History  : ? ")

        # take input from the user
        choice = input("Enter choice(+,-,*,/,^,%,#,$,?): ")
        print(choice)
        select_op(choice, history)

main()

There is a significant amount of further optimization that can be done with your code as well, like creating an dictionary to hold the operators and their corresponding functions, also you can use another loop for selecting the numbers to decrease the amount of repeated code.

Here is the same solution as above but optimized for readability and less code duplication.

def add(a,b):
    return a+b

def subtract(a,b):
    return a-b

def multiply (a,b):
    return a*b

def divide(a,b):
    try:
        return a/b
    except Exception as e:
        print(e)

def power(a,b):
   return a**b

def remainder(a,b):
   return a%b

def select_op(choice, history):
    if (choice == '#'):
        print("Done. Terminating")
        exit()
    elif (choice == '$'):
        return main()
    elif (choice in ('+','-','*','/','^','%')):
        nums = []
        for _ in range(2):
            while (True):
                numstr = str(input("Enter first number: "))
                print(numstr)
                if numstr.endswith('$'):
                    return main()
                if numstr.endswith('#'):
                    print("Done. Terminating")
                    exit()
                try:
                    num = float(numstr)
                    nums.append(num)
                    break
                except:
                    print("Not a valid number,please enter again")
                    continue
        funcmap = {
            "+": add,
            "-": subtract,
            "*": multiply,
            "/": divide,
            "^": power,
            "%": remainder
        }
        if choice in funcmap:
            num1,num2 = nums
            result = funcmap[choice](num1, num2)
            msg = "{0} {1} {2} = {3}".format(num1, choice, num2, result)
            print(msg)
            history.append(msg)
        else:
            print("Something Went Wrong")
    elif choice=='?':
        if len(history) ==0:
            print("No past calculations to show")
        else:
            b="\n".join(history)
            print(b)
    else:
        print("Unrecognized operation")
        return main()

def main():
    history = []
    while True:
        print("Select operation.")
        print("1.Add      : + ")
        print("2.Subtract : - ")
        print("3.Multiply : * ")
        print("4.Divide   : / ")
        print("5.Power    : ^ ")
        print("6.Remainder: % ")
        print("7.Terminate: # ")
        print("8.Reset    : $ ")
        print("8.History  : ? ")

        # take input from the user
        choice = input("Enter choice(+,-,*,/,^,%,#,$,?): ")
        print(choice)
        select_op(choice, history)

main()

This sort of thing is best done using a control dictionary. Also, there's no need to write the add, subtract etc functions as they're all available in the operator module.

This simplifies matters considerably:

import operator

history = []

control = {
    '+': (operator.add, 'Add'),
    '-': (operator.sub, 'Subtract'),
    '*': (operator.mul, 'Multiply'),
    '/': (operator.truediv, 'Divide'),
    '^': (operator.pow, 'Power'),
    '%': (operator.mod, 'Remainder'),
    '#': (None, 'Terminate'),
    '$': (None, 'Reset'),
    '?': (None, 'History')
}

while True:
    for i, (k, v) in enumerate(control.items(), 1):
        print(f'{i}. {v[1]:<10}: {k} ')
    option = input(f'Choose option ({",".join(control)}): ')
    match option:
        case '#':
            break
        case '$':
            history = []
        case '?':
            print(*history, sep='\n')
        case _:
            if t := control.get(option):
                a = input('Input first value: ')
                b = input('Input second value: ')
                try:
                    r = t[0](float(a), float(b))
                    print(res := f'{a} {option} {b} = {r}')
                    history.append(res)
                except (ValueError, ZeroDivisionError) as e:
                    print(e)
            else:
                print('Invalid option\x07')
Related