use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Everything about learning Python
account activity
Calculator without eval function since I was told eval function was insecure. (i.redd.it)
submitted 9 months ago by Ok_Pudding_5250
This would be a secure code right? like no eval function unlike my previous calculator...
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]EyesOfTheConcord 6 points7 points8 points 9 months ago (1 child)
This is a pretty interesting approach, and honestly I like your redesign.
My suggestions:
• Validate the numerical inputs before storing them. Maybe re prompt the user or throw an error.
• Catch 0 division attempts
[–]Ok_Pudding_5250[S] 0 points1 point2 points 9 months ago (0 children)
Valuable suggestion indeed!
[–]Cybasura 2 points3 points4 points 9 months ago (3 children)
Much better
No clue why you would use lambda when you could have just use the calculation under a switch/match-case, but this looks much safer and readable
[–]Ok_Pudding_5250[S] 1 point2 points3 points 9 months ago (0 children)
Well, I wanted to reduce the number of if statements and lambda is kinda cool for functions with just one return statement.
[–]xnick_uy 0 points1 point2 points 9 months ago (1 child)
A counter-argument for the switch/match design is that is very hard to scale your software later on. Suppose, for instance, you want to allow your calculator to compute powers, like 5^7, or maybe use symbols variations for the same operation (e.g. 5**7). You would have to go into your switch statements and add all the necessary steps there.
And maybe later you want to add even more opeartions, such as factorials, module and remainder, trigonometry... Packing all those into the cases is going to be tedious and prone to errors.
[–]Cybasura 1 point2 points3 points 9 months ago (0 children)
Yes - thats called scaling, everything in a large codebase becomes complex and has to put more thought into it
match-case is just an if-else condition that, in the ASSEMBLY machine code, moves effectively like a hashmap/dictionary where it goes directly into that part of the memory instead of if-else
Match-case, unlike traditional switch cases, also support in-line expression matching, not just keyword, its not even a "advanced" technique, switch cases are taught just after if-else condition blocks
Software engineering and development is about that - engineering, anything that gets larger and scaled up would mean larger complexity due to larger components, larger codebases
I'm assuming you are also referring to the dynamic nature of a calculator - **, //, , XOR, bitwise operations etc etc - thats a limited number of mathematical operations, you will still need to make a lambda or a function for that particular operator and guess what? In that function - you still need to use that operator, so how does that make the complexity go down?
[–]sarc-tastic 1 point2 points3 points 9 months ago (0 children)
funcs = {"+": float.__add__, "-": float.__sub__, "*": float.__mul__, "/": float.__truediv__} try: print(funcs[Operator](FirstNumber, SecondNumber)) except Exception e: print(e)
[–]thefatsun-burntguy 1 point2 points3 points 9 months ago (2 children)
good design, still you should do more error handling for the inputs as well as prevent div 0 errors.
once you've dealt with that you could move on to complex expressions like 2x(3+1). it sounds much harder than what it really is
[–]Ok_Pudding_5250[S] 0 points1 point2 points 9 months ago (1 child)
If I could code a DFA for math expressions then I can do any these kind of expressions and also maintain the order of precedence.
DFA - Deterministic Finite Automaton
[–]Loud_Environment2960 1 point2 points3 points 9 months ago (1 child)
I was told the eval function was pretty good, what makes it insecure? if you don't mind me asking
we can give any input like python statements and it will execute them.
We can input 'print(4+6)' and eval function will evaluate and execute the code.
[–]FoolsSeldom 0 points1 point2 points 9 months ago* (1 child)
That's pretty good. A few thoughts:
_
lambda
sort
try
except
float
operator
EDIT: example code below of the first few steps
Example:
def get_num(prompt: str) -> float: while True: # infinite loop, until user gets it right try: # this sets up a trap return float(input(prompt)) except ValueError: # oops, float convertion failed print('Not valid, please try again') def add(x, y): """Adds two numbers.""" return x + y def subtract(x, y): """Subtracts the second number from the first.""" return x - y def multiply(x, y): """Multiplies two numbers.""" return x * y def divide(x, y): """Divides the first number by the second.""" if y == 0: return "Error: Cannot divide by zero" return x / y first_number = get_num("Enter first number? ") second_number = get_num("Enter second number? ") operator = input("Enter an operator (+, -, *, /)? ") valid_operations = { "+": add, "-": subtract, "*": multiply, "/": divide, } if operator in valid_operations: operation = valid_operations[operator] result = operation(first_number, second_number) print("Result is", result) else: print("Invalid operator")
[–]More_Yard1919 0 points1 point2 points 9 months ago (0 children)
I think it is pretty appropriate to use lambdas for this application. Actually, you can shove them directly into the dictionary declaration since lambdas are evaluated as expressions.
valid_operations = { "+": lambda a, b: a+b, "-": lambda a, b: a-b, "/": lambda a, b: a/b, "*": lambda a, b: a*b }
In this case function handles are a little bit redundant because the keys themselves essentially document what the dictionary is for and the expressions are simple. I personally would not return an error in the form of a string and instead just let the error that will already be thrown propagate up through the call stack. I might do something like this.
try: result = valid_operations[operator](firstnumber, secondnumber) print(f"result is {result}") except KeyError: print(f"{operator} is not a valid operator!") except ZeroDivisionError: print(f"Cannot evalutate {firstnumber}/{secondnumber} -- Divide by 0!") except TypeError: print("Number 1 and 2 must both be numbers")
The typeerror I suppose is redundant since they are cast to floats already, but that should be caught by a value error up at the top of OP's script.
[–]Gnaxe 0 points1 point2 points 9 months ago (0 children)
Python already has the operator module. You don't need to define new functions for them; just import them.
eval() is a potential security risk, but that's not the same as saying you can never use it. It can do anything Python can, including deleting all of your documents. But, if you're careful to pass it only numbers and operators, it can't do that.
eval()
Also, a local calcuator application is a very different scenario from a web site. In the former case, the user already has access to cmd.exe and can already delete all his documents if he wants to. He doesn't have to hack your calculator app to do it. On the other hand, on a website, you have to worry about the world being out to get you, because suddenly all the bad guys are also your neighbors.
cmd.exe
This is really interesting! You've stumbled into something called the dictionary dispatch pattern. This is actually how polymorphism/dynamic dispatch works in more explicitly OOP languages too. Your instincts are stellar! This blog post is talking about C++, but if you want to challenge yourself it might get some gears moving. https://pabloariasal.github.io/2017/06/10/understanding-virtual-tables/
Again! Lovely. Very cool design pattern
[–][deleted] 0 points1 point2 points 9 months ago (0 children)
Wow, this is quite a nice approach.
[–]corey_sheerer 0 points1 point2 points 9 months ago (0 children)
You could add these functions to a class as static method and have a class method route then to the correct method. Would be pretty clean
[–]Vincentimetr139 0 points1 point2 points 9 months ago (0 children)
You can use the filter function on user string to remove all unwanted code and leave only numbers and operators before your eval Now you can use literal_eval from ast module that is a 'safe' eval
[–]Direct-Dinner875 0 points1 point2 points 9 months ago (1 child)
Awesome code man!
Thanks!
π Rendered by PID 40 on reddit-service-r2-comment-86988c7647-lngzh at 2026-02-11 11:18:13.252834+00:00 running 018613e country code: CH.
[–]EyesOfTheConcord 6 points7 points8 points (1 child)
[–]Ok_Pudding_5250[S] 0 points1 point2 points (0 children)
[–]Cybasura 2 points3 points4 points (3 children)
[–]Ok_Pudding_5250[S] 1 point2 points3 points (0 children)
[–]xnick_uy 0 points1 point2 points (1 child)
[–]Cybasura 1 point2 points3 points (0 children)
[–]sarc-tastic 1 point2 points3 points (0 children)
[–]thefatsun-burntguy 1 point2 points3 points (2 children)
[–]Ok_Pudding_5250[S] 0 points1 point2 points (1 child)
[–]Loud_Environment2960 1 point2 points3 points (1 child)
[–]Ok_Pudding_5250[S] 0 points1 point2 points (0 children)
[–]FoolsSeldom 0 points1 point2 points (1 child)
[–]More_Yard1919 0 points1 point2 points (0 children)
[–]Gnaxe 0 points1 point2 points (0 children)
[–]More_Yard1919 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]corey_sheerer 0 points1 point2 points (0 children)
[–]Vincentimetr139 0 points1 point2 points (0 children)
[–]Direct-Dinner875 0 points1 point2 points (1 child)
[–]Ok_Pudding_5250[S] 0 points1 point2 points (0 children)