Complete Implementation
import math
import operator
class Calculator:
OPERATIONS = {
"+": operator.add, "-": operator.sub,
"*": operator.mul, "/": operator.truediv,
"**": operator.pow, "%": operator.mod,
}
def __init__(self):
self.history = []
def calculate(self, a, op, b):
if op not in self.OPERATIONS:
raise ValueError(f"Unknown operator: {op}")
if op == "/" and b == 0:
raise ZeroDivisionError("Cannot divide by zero")
result = self.OPERATIONS[op](a, b)
self.history.append(f"{a} {op} {b} = {result}")
return result
def sqrt(self, n):
if n < 0:
raise ValueError("Cannot take sqrt of negative number")
result = math.sqrt(n)
self.history.append(f"sqrt({n}) = {result}")
return result
def main():
calc = Calculator()
print("Python Calculator | ops: + - * / ** % | sqrt | history | quit")
while True:
try:
expr = input("> ").strip().lower()
if expr == "quit": break
if expr == "history":
print("\n".join(f" {i+1}. {e}" for i, e in enumerate(calc.history)) or "No history.")
continue
if expr.startswith("sqrt "):
print(calc.sqrt(float(expr[5:])))
continue
parts = expr.split()
if len(parts) == 3:
a, op, b = float(parts[0]), parts[1], float(parts[2])
print(calc.calculate(a, op, b))
else:
print("Format: <num> <op> <num>")
except (ValueError, ZeroDivisionError) as e:
print(f"Error: {e}")
except KeyboardInterrupt:
break
if __name__ == "__main__":
main() Running
python calculator.py
# > 5 + 3 → 8.0
# > sqrt 16 → 4.0
# > history🏋️ Practical Exercise
Enhance the calculator:
- Add support for exponentiation and modulo operations.
- Handle division by zero gracefully instead of crashing.
- Loop so the user can perform multiple calculations until they quit.
- Validate input so non-numeric entries show a friendly error.
🔥 Challenge Exercise
Turn the calculator into a small expression evaluator that respects operator precedence (e.g. handle 2 + 3 * 4 correctly), support parentheses, and keep a history of previous results the user can reference. Structure the code into clear functions and add error handling for malformed input. Bonus: add unit tests for the core evaluation logic.
📋 Summary
- This project builds an interactive command-line calculator.
- Core operations are organized into small, testable functions.
- User input is validated and converted safely with error handling.
- Division by zero and bad input are handled gracefully rather than crashing.
- A loop lets the user perform repeated calculations until they quit.
- The logic can be extended with precedence, history, tests, or a GUI.
Interview Questions on Building a Calculator
- How would you structure a calculator program into functions?
- How do you handle invalid or non-numeric user input?
- How do you prevent a division-by-zero crash?
- How would you support operator precedence?
- How do you keep a CLI program running until the user chooses to exit?
- How would you add unit tests for the calculation logic?
- How could you extend it into a GUI or web app?
Related Topics
FAQ
Wrap the input conversion in try/except ValueError and re-prompt, and check for division by zero before dividing. Handling these edge cases turns a crash into a friendly message.
For full expressions like 2 + 3 * 4, parse the input rather than evaluating left-to-right — implement the shunting-yard algorithm, build an expression tree, or (carefully, with trusted input only) use Python’s own parsing. A simple menu-driven calculator avoids this by doing one operation at a time.
eval() to evaluate expressions? +Avoid eval() on untrusted input — it can execute arbitrary code. For learning with your own input it works, but a real tool should use a safe parser or ast.literal_eval for limited cases.
Reuse the calculation functions and add a front end — tkinter for a desktop GUI, or a small Flask/FastAPI app for a web version. Keeping logic separate from the interface makes this swap easy.
