CCCPaste

example cli calculator with menu

import math
import operator

# Use a dictionary to define the menu of operations.
# Structure: key: (description, function, number_of_arguments, symbol)
OPERATIONS = {
    '1': ("Add", operator.add, 2, '+'),
    '2': ("Subtract", operator.sub, 2, '-'),
    '3': ("Multiply", operator.mul, 2, '*'),
    '4': ("Divide", operator.truediv, 2, '/'),
    '5': ("Power", operator.pow, 2, '**'),
    '6': ("Square Root", math.sqrt, 1, '√'),
    '7': ("Exit", None, 0, None)
}

def get_operands(num_args: int) -> list[float]:
    """Prompts the user for the required number of operands and validates them."""
    operands = []
    for i in range(num_args):
        while True:
            try:
                prompt = f"Enter the {i + 1}{'st' if i == 0 else 'nd' if i == 1 else 'rd' if i == 2 else 'th'} number: "
                if num_args == 1:
                    prompt = "Enter the number: "
                num = float(input(prompt))
                operands.append(num)
                break
            except ValueError:
                print("Invalid input. Please enter a number.")
    return operands

def present_menu(operations: dict) -> str:
    """Displays the menu of options and returns a validated user choice."""
    print("\nSelect operation.")
    for key, (description, _, _, _) in operations.items():
        print(f"{key}. {description}")

    while True:
        choice = input(f"Enter choice ({', '.join(operations.keys())}): ")
        if choice in operations:
            return choice
        else:
            print("Invalid choice. Please select a valid option.")

def main():
    """Main function to run the calculator."""
    while True:
        choice = present_menu(OPERATIONS)
        description, operation_func, num_args, symbol = OPERATIONS[choice]

        if operation_func is None:  # Exit condition
            print("bye")
            break

        operands = get_operands(num_args)

        # Add error handling for specific operations
        if operation_func == operator.truediv and operands[1] == 0:
            print("Error: Cannot divide by zero.")
        elif operation_func == math.sqrt and operands[0] < 0:
            print("Error: Cannot take the square root of a negative number.")
        else:
            result = operation_func(*operands)
            # Format the output string based on the operation
            if num_args == 2:
                print(f"{operands[0]} {symbol} {operands[1]} = {result}")
            elif num_args == 1:
                print(f"{symbol}{operands[0]} = {result}")

        # Ask user if they want to continue
        while True:
            next_calc = input("Continue? (y/n): ").lower()
            if next_calc in ('y', 'n'):
                break
            else:
                print("Invalid input, Enter y or n.")

        if next_calc == 'n':
            print("bye")
            break

if __name__ == "__main__":
    main()