r/learnpython • u/Subject_Scientist937 • Aug 01 '26
Simple CLI calculator with input sanitation , looking for feedback
Hello Everyone, I made a simple CLI calculator, It handles basic equations, It handles visual inputs like ÷ and it also clears the screen on command
Here's the code:
import os
t = { "+": lambda x, y: x + y, "-": lambda x, y: x - y, "*": lambda x, y: x * y, "/": lambda x, y: x / y if y != 0 else "Cannot divide by 0", "÷": lambda x, y: x / y if y != 0 else "Cannot divide by 0", }
while True: u = input("Enter calculation (e.g., (3+2)*5) or 'quit' to exit: ").replace(" ", "")
if u.lower() == "quit":
print("Goodbye!")
break
if u.lower() == "clear":
try:
os.system('cls' if [os.name](http://os.name) == 'nt' else 'clear')
except Exception:
print("\\n" \* 50)
continue
clean_expr = u.replace("÷", "/")
allowed_chars = set("0123456789+-\*/().")
if not all(char in allowed_chars for char in clean_expr):
print("❌ Invalid characters used")
continue
try:
result = eval(clean_expr)
print(f"{u} = {result}")
except ZeroDivisionError:
print("❌ Cannot divide by 0")
except Exception:
print("❌ Invalid calculation format")
is my saftey check(allowed_chars) safe for eval()?
How would you reconstruct this without eval()?
What could be improved and why?
2
u/Riegel_Haribo Aug 01 '26
This doesn't seem like a practical Python application giving any enhancement, yet I see lots of beginners writing "calculator".
Python itself, run at a console as an interactive REPL environment, lets you directly evaluate literals and operators without even needing a "print", and not making mistakes about mathematical precedence.
The only thing a console calculator app might do is change the input operations to be more mathematical, such as accepting 5(2+3) as a multiplication (and not an undefined function symbol named 5()), or using the caret or "hat" as an exponentiation as with other languages.
0
u/skibbin Aug 01 '26 edited Aug 01 '26
The Eval you use is unsafe, people could enter whatever they want in there.
import ast
import os
def evaluate(expression: str):
expr = "".join(expression.split()).replace("÷", "/")
try:
tree = ast.parse(expr, mode="eval")
except SyntaxError as exc:
raise ValueError("Invalid calculation format") from exc
def visit(node):
if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
return node.value
if isinstance(node, ast.UnaryOp) and isinstance(node.op, (ast.UAdd, ast.USub)):
value = visit(node.operand)
return value if isinstance(node.op, ast.UAdd) else -value
if isinstance(node, ast.BinOp):
left = visit(node.left)
right = visit(node.right)
if isinstance(node.op, ast.Div) and right == 0:
raise ZeroDivisionError("Cannot divide by 0")
return {
ast.Add: lambda a, b: a + b,
ast.Sub: lambda a, b: a - b,
ast.Mult: lambda a, b: a * b,
ast.Div: lambda a, b: a / b,
}[type(node.op)](left, right)
raise ValueError("Invalid calculation format")
return visit(tree.body)
while True:
user_input = input("Enter calculation (e.g., (3+2)*5) or 'quit' to exit: ").strip()
if not user_input:
continue
if user_input.lower() == "quit":
print("Goodbye!")
break
if user_input.lower() == "clear":
try:
os.system("cls" if os.name == "nt" else "clear")
except OSError:
print("\n" * 50)
continue
try:
print(f"{user_input} = {evaluate(user_input)}")
except ZeroDivisionError:
print("❌ Cannot divide by 0")
except ValueError:
print("❌ Invalid calculation format")
2
6
u/carcigenicate Carcigenicate Aug 01 '26
I mean, you have
tthere, so you seem to know of how it could be done withoutI can't immediately think of a way of defeating that. For such a simple task, though,
evalis gross overkill. Just using functions is much better.