Day 010 of the 100 Days of Python challenge builds a command-line calculator for addition, subtraction, multiplication, and division. It also lets the user chain operations together, using the result of one calculation as the starting point for the next.

The most interesting idea in this project is using a dictionary to map operator symbols directly to functions, which avoids a long chain of if/elif statements for choosing which calculation to run. It’s a pattern worth understanding well, since it scales cleanly as you add more operations.

This guide walks through the complete Day 010 source code, explains the operator-dictionary pattern and the chaining logic, and points out two real gaps in the program’s error handling.

Project Overview

Each arithmetic operation has its own function. A dictionary maps an operator symbol to the matching function:

operations = {
    "+": addition,
    "-": subtraction,
    "*": multiplication,
    "/": division,
}

This lets the calculator choose and call an operation without a long chain of conditional statements. The get_number() function repeatedly asks for input until it can convert the response to a float. After calculating a result, the user can continue with that answer or start a new calculation.

Source Code

The Day 010 project is contained in day010/main.py in the 100daysofpython repository:

from art import LOGO

print(LOGO)
print("*******************************************")
print("Welcome to The Calculator!")
print("*******************************************")

def addition(n1, n2):
    return n1 + n2

def subtraction(n1, n2):
    return n1 - n2

def multiplication(n1, n2):
    return n1 * n2

def division(n1, n2):
    return n1 / n2

operations = {
    "+": addition,
    "-": subtraction,
    "*": multiplication,
    "/": division
}

def get_number(prompt):
    while True:
        try:
            return float(input(prompt))
        except ValueError:
            print("Invalid input! Please enter a number.")

def calculator():
    num1 = get_number("What is the first number?: ")
    should_accumulate = True

    while should_accumulate:
        for symbol in operations:
            print(symbol)

        while True:
            operation_symbol = input("Pick an operation: ")
            if operation_symbol in operations:
                break
            print("Invalid operator! Please choose +, -, * or /")

        num2 = get_number("What is the next number?: ")

        answer = operations[operation_symbol](num1, num2)
        print(f"{num1} {operation_symbol} {num2} = {answer}")

        choice = input(f"Type 'y' to continue calculating with {answer}, or type 'n' to start a new calculation: ")

        if choice == "y":
            num1 = answer
        else:
            should_accumulate = False
            print("\n" * 20)
            calculator()

calculator()

How the Program Works

Mapping Operators to Functions

operations = {
    "+": addition,
    "-": subtraction,
    "*": multiplication,
    "/": division
}

In Python, functions are values, just like numbers or strings — they can be stored in a dictionary, passed around, and called later. This dictionary maps each operator symbol directly to the function that implements it, so looking up and calling the right operation is a single line:

answer = operations[operation_symbol](num1, num2)

operations[operation_symbol] retrieves the matching function (say, addition), and the trailing (num1, num2) immediately calls it. Adding a new operator later — like % for modulo — only requires writing a new function and adding one entry to the dictionary, with no changes needed to the lookup logic itself.

Validating Numeric Input With a Reusable Function

def get_number(prompt):
    while True:
        try:
            return float(input(prompt))
        except ValueError:
            print("Invalid input! Please enter a number.")

Rather than duplicating the same validation loop for both the first and second number, get_number() is a small reusable function that keeps asking until it gets valid input, then returns the moment it succeeds — a clean way to avoid repeating the same try/except pattern twice.

Chaining Calculations

if choice == "y":
    num1 = answer

When the user chooses to keep calculating, the previous answer becomes the new num1, and the loop continues. This is what allows something like 10 + 5, then * 2 on the result, to work as two separate interactive steps rather than one expression.

Two Real Gaps in the Error Handling

No Protection Against Division by Zero

def division(n1, n2):
    return n1 / n2

Unlike get_number(), which validates its input before returning, division() performs no checks at all. If the user picks / and enters 0 as the second number, Python raises a ZeroDivisionError, which nothing in this program catches — the calculator crashes instead of showing a friendly error message.

Restarting Uses Recursion Instead of a Loop

else:
    should_accumulate = False
    print("\n" * 20)
    calculator()

When the user wants to start a new calculation, the program calls calculator() again from inside itself — this is recursion. It works fine for normal use, but each time someone starts a new calculation, Python adds another frame to the call stack, and those frames aren’t released until every nested call eventually returns. Restart enough times in one session (well beyond normal use, but not impossible in an automated test), and Python’s default recursion limit would eventually raise a RecursionError. A while True loop wrapping the whole function body would achieve the same restart behavior without that risk.

What This Project Teaches

Day 010 combines:

  • Functions as values, stored and looked up in a dictionary
  • Reusable input-validation functions
  • Loops for chaining calculations using a running result
  • Recursion as an (imperfect) way to restart a program’s flow
  • Where a program’s error handling has gaps, and why that matters

The project is intentionally simple and does not implement mathematical precedence — each operation is performed in the order the user selects it, so 10 + 5 * 2 entered as two separate steps calculates (10 + 5) * 2, not 10 + (5 * 2).

Running the Project

git clone https://github.com/victorhugo81/100daysofpython.git
cd 100daysofpython/day010
python main.py

Possible Next Steps

Once you understand the existing code, try extending it:

  • Add a try/except ZeroDivisionError around the division call, so dividing by zero shows a friendly message instead of crashing
  • Replace the recursive restart with a while True loop around the whole calculator, avoiding any recursion depth concerns
  • Add more operators, like exponentiation (**) or modulo (%), to see how little code the dictionary pattern requires for each new one
  • Track and display a history of every calculation performed in the session

Conclusion

Day 010 of the 100 Days of Python challenge shows how mapping operators to functions in a dictionary keeps a calculator’s logic clean and easy to extend, while chaining results through a loop enables multi-step calculations. It’s also a useful case study in incomplete error handling — the missing division-by-zero check and the recursive restart are both easy to miss on a first read, which is exactly why tracing through every branch of a program’s logic matters.

View the Day 010 source code on GitHub, then continue through the repository’s project index as you build more Python programs, one day and one small project at a time.