What You'll Build
A Python command-line calculator that runs in the terminal. It shows a menu of operations, asks for two numbers, prints the result, and loops back for the next calculation. Type q to quit. Invalid input is caught and shown gracefully instead of crashing.
- Menu-driven interface — add, subtract, multiply, divide, power
- Reads numbers from the user with
input() - Keeps running until you quit
- Handles invalid input without crashing
- Prevents division by zero gracefully
- Keeps a history of all calculations
Note about the preview: Python runs on your computer, not in a browser. This preview is a simulated terminal that mimics the exact behaviour of the finished calculator. When you run the real code, it will look like this in your terminal.
What You'll Learn
input()andprint(): reading from and writing to the terminal- Type conversion: converting strings to numbers with
float() if / elif / else: branching based on user choiceswhileloops: keeping the program running until the user quits- Functions: organising code with
def try / except: catching errors instead of crashing- f-strings: formatting output cleanly
- Lists and dictionaries: storing the history of calculations
Make Sure Python Is Installed
If you haven't installed Python yet, follow our guide — it takes 5 minutes:
Verify Python is installed by opening a terminal and typing:
python --version
You should see something like Python 3.12.0. If not, install it first and come back.
Start with the Simplest Version
Create a file called calculator.py. We'll build this in stages — start with the simplest possible version, then improve it.
# calculator.py — version 1 print("Simple Calculator") a = float(input("Enter first number: ")) b = float(input("Enter second number: ")) print(f"{a} + {b} = {a + b}") print(f"{a} - {b} = {a - b}") print(f"{a} * {b} = {a * b}")
Run it:
python calculator.py
Working calculator. It runs, asks for two numbers, prints three results, and exits. Now we make it useful.
Why float(input())? input() always returns a string — even if the user types a number. float() converts that string to a decimal number. Without it, "5" + "3" gives "53" instead of 8.
Add a Menu and Let the User Choose
Now the calculator asks which operation to perform. We use if / elif / else to branch based on the user's choice.
# calculator.py — version 2 print("=== Python Calculator ===") print("1. Add") print("2. Subtract") print("3. Multiply") print("4. Divide") print("5. Power") print() choice = input("Choose an operation (1-5): ") a = float(input("Enter first number: ")) b = float(input("Enter second number: ")) if choice == "1": result = a + b print(f"{a} + {b} = {result}") elif choice == "2": result = a - b print(f"{a} - {b} = {result}") elif choice == "3": result = a * b print(f"{a} * {b} = {result}") elif choice == "4": result = a / b print(f"{a} / {b} = {result}") elif choice == "5": result = a ** b print(f"{a} ^ {b} = {result}") else: print("Invalid choice.")
Now the user picks what they want. But there are still problems:
- If they type "abc" for a number, the program crashes
- If they divide by zero, the program crashes
- After one calculation, the program exits
Let's fix all three.
Wrap Everything in a Loop
To keep running until the user quits, wrap the whole program in a while loop. We use the special value True for an infinite loop that only ends when we break out of it.
# calculator.py — version 3 while True: print("\n=== Python Calculator ===") print("1. Add 2. Subtract") print("3. Multiply 4. Divide") print("5. Power q. Quit") choice = input("\nChoose an operation: ").strip().lower() if choice == "q": print("Goodbye!") break # ... rest of the calculator here ...
What's .strip().lower()? .strip() removes whitespace from both ends (so " q " becomes "q"). .lower() makes everything lowercase (so "Q" becomes "q"). This makes the program more forgiving — the user doesn't have to type perfectly.
Add Error Handling
Now the important part — catching errors instead of crashing. Python uses try / except for this.
# Wrapping risky code in try/except try: a = float(input("Enter first number: ")) b = float(input("Enter second number: ")) except ValueError: print("❌ That's not a valid number. Try again.") continue # jump back to the top of the while loop
ValueError is what float() raises when it can't convert a string to a number. If the user types "abc" and we try float("abc"), Python raises that error. Our except catches it, prints a friendly message, and continue skips to the next iteration of the loop.
For division by zero, we handle it inline:
elif choice == "4": if b == 0: print("❌ Cannot divide by zero.") continue result = a / b print(f"{a} / {b} = {result}")
Extract Functions for Cleaner Code
The code is getting long. Time to break it into functions. Each one does a single job — this is how real Python code is written.
# calculator.py — final version def show_menu(): """Print the main menu.""" print("\n=== Python Calculator ===") print("1. Add 2. Subtract") print("3. Multiply 4. Divide") print("5. Power h. History") print("q. Quit") def get_numbers(): """Ask the user for two numbers. Returns them or None on error.""" try: a = float(input("Enter first number: ")) b = float(input("Enter second number: ")) return a, b except ValueError: print("❌ That's not a valid number.") return None def calculate(choice, a, b): """Perform the chosen operation. Returns result or None on error.""" if choice == "1": return a + b, "+" elif choice == "2": return a - b, "-" elif choice == "3": return a * b, "*" elif choice == "4": if b == 0: print("❌ Cannot divide by zero.") return None, None return a / b, "/" elif choice == "5": return a ** b, "^" else: print("❌ Invalid choice.") return None, None
Add a History Feature
To make it more useful, keep a list of every calculation the user performs. A list works perfectly for this.
def main(): """The main program loop.""" history = [] # empty list to start print("Welcome to the Python Calculator!") while True: show_menu() choice = input("\nChoose: ").strip().lower() # Quit if choice == "q": print("\nGoodbye! 👋") break # Show history if choice == "h": if not history: print("No calculations yet.") else: print("\n--- History ---") for i, entry in enumerate(history, 1): print(f"{i}. {entry}") continue # Get numbers nums = get_numbers() if nums is None: continue a, b = nums # Calculate result, op = calculate(choice, a, b) if result is None: continue # Show result line = f"{a} {op} {b} = {result}" print(f"\n✅ {line}") history.append(line) # Only run when this file is executed directly if __name__ == "__main__": main()
Save the file and run it: python calculator.py. The calculator should greet you, show the menu, and accept input. Type h to see the history. Type q to quit.
Understand the Big Ideas
1. Why input() always returns a string
Python's input() function is designed to accept any text — names, sentences, phone numbers, whatever. It can't guess that you want a number. So it always returns a string. You convert with int() or float() when you need a number.
age = input("Your age: ") # age is a string, e.g. "25" age = int(age) # now it's a number, 25 # Or in one line: age = int(input("Your age: "))
2. try / except — Python's version of try / catch
Same idea as JavaScript's try / catch, different keyword. In Python:
try: result = int("hello") except ValueError: print("That's not a number.")
You can catch different error types (ValueError, ZeroDivisionError, FileNotFoundError) and handle each differently. Catching the specific error you expect is better than catching everything — it hides bugs.
3. f-strings — the cleanest way to format strings
name = "Sarah" age = 25 # Old ways (avoid): print("Hello, " + name + ". You are " + str(age) + ".") print("Hello, {}. You are {}.".format(name, age)) # f-string (use this): print(f"Hello, {name}. You are {age}.")
f-strings are faster, more readable, and let you embed expressions directly: f"Next year you'll be {age + 1}".
4. continue vs break
break— exit the loop entirelycontinue— skip the rest of this iteration, jump back to the top of the loop
In our calculator, when the user enters an invalid number, we continue — skip everything else this round and show the menu again. When they type q, we break — exit for good.
5. The if __name__ == "__main__" pattern
Every real Python file ends with this line. It means: "only run main() if this file is executed directly — not if it's imported by another file."
You don't need to fully understand this yet. Just know that it's the standard way to write a Python program's entry point. Add it to every script you write.
Practice Challenges
🟢 Beginner
- Add a square root option (single number input)
- Add a modulo option (
a % b) - Add a "clear history" command
🟡 Intermediate
- Add scientific operations: sin, cos, tan, log (import
math) - Save the history to a text file so it persists between sessions
- Add an undo command that removes the last entry from history
🔴 Advanced
- Accept full expressions like "5 + 3 * 2" using
eval()(safely!) - Add a graphing mode using
matplotlibto plot y = f(x) - Rewrite it as a GUI app with
tkinter— buttons and a display - Turn it into a web API with
Flaskso other programs can call it
Full Source Code
The complete calculator.py in one block:
"""calculator.py — a command-line calculator.""" def show_menu(): print("\n=== Python Calculator ===") print("1. Add 2. Subtract") print("3. Multiply 4. Divide") print("5. Power h. History") print("q. Quit") def get_numbers(): try: a = float(input("Enter first number: ")) b = float(input("Enter second number: ")) return a, b except ValueError: print("❌ That's not a valid number.") return None def calculate(choice, a, b): if choice == "1": return a + b, "+" elif choice == "2": return a - b, "-" elif choice == "3": return a * b, "*" elif choice == "4": if b == 0: print("❌ Cannot divide by zero.") return None, None return a / b, "/" elif choice == "5": return a ** b, "^" else: print("❌ Invalid choice.") return None, None def main(): history = [] print("Welcome to the Python Calculator!") while True: show_menu() choice = input("\nChoose: ").strip().lower() if choice == "q": print("\nGoodbye! 👋") break if choice == "h": if not history: print("No calculations yet.") else: print("\n--- History ---") for i, entry in enumerate(history, 1): print(f"{i}. {entry}") continue nums = get_numbers() if nums is None: continue a, b = nums result, op = calculate(choice, a, b) if result is None: continue line = f"{a} {op} {b} = {result}" print(f"\n✅ {line}") history.append(line) if __name__ == "__main__": main()
Common Mistakes & Fixes
❌ "SyntaxError: invalid syntax" on print
In Python 3, print is a function and needs parentheses: print("hello"), not print "hello". If you're following Python 2 tutorials, they'll be wrong for modern Python.
❌ "TypeError: can only concatenate str (not 'int') to str"
You're trying to add a string and a number: "Age: " + 25. Fix it with an f-string: f"Age: {25}", or convert: "Age: " + str(25).
❌ "NameError: name 'x' is not defined"
You're using a variable before creating it, or you have a typo in the name. Python is case-sensitive — Age and age are different variables.
❌ "IndentationError"
Python uses indentation (whitespace) to define code blocks — not curly braces like JavaScript. Every line inside a function, if statement, or loop must be indented consistently. Use 4 spaces (not tabs).
❌ "ValueError: could not convert string to float: 'abc'"
The user typed something that isn't a number. Wrap the conversion in try/except (as shown in step 4).
❌ "ZeroDivisionError"
Division by zero raises this in Python. Check b == 0 before dividing, or catch the error in try/except.
❌ Program exits after one calculation
You forgot the while True: loop. Without it, the program runs top-to-bottom once and exits.