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 ZeroDivisionErroraround the division call, so dividing by zero shows a friendly message instead of crashing - Replace the recursive restart with a
while Trueloop 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.
