J. Bowen
J. Bowen

Reputation: 11

Python 3 Calculator, how to get around eval

I'm working through Python Programming: An Introduction to Computer Science (2nd edition). At the end of the second chapter, one of the exercises is to design a calculator. Prior to this, he has been using eval() to do calculations. I know that using eval is bad for security, but I dont know how to get around using it. I could always use it now and worry about it later, but I want to build good habits.

I want the user to enter their desired calculation as one line, like this:

>>> input('Input your expression: ')
Input your expression: 4 * 5 / 2

I've already looked at this post Pros and Cons on designing a calculator with eval . The answer gave him a link that showed how you could get around it. The way he did it seemed quite convoluted, and I don't understand how he did it.

I think I need eval() for this. My code for the calculator is below. Thank you for the help!

# Calculator.py
# This program will allow the user to input a mathematical expression (using python syntax)
# it will then evaluate the expression and print the result. It will unfortunately use eval
# but I dont know how to get around this problem. The program will loop to allow for
# multiple calculations.

expression = 'blank'

print('Calculator')
print(' ')
print('Welcome! Please input your desired expression, using python syntax.')
print('When you are finished, input end, and the program will finish.')

# Until the user inputs end, the calculator will continue to repeat.
while expression != 'end':
    print('')
    expression= input('Input your expression: ')
# Checks if the last digit of expression is a digit. I think this is fairly foolproof.
# I used last digit instead of first, bc a negative sign could have been in the first digit.
    if expression[len(expression)-1].isdigit():
        print('= ', eval(expression))
# A way to distinguish between 'end' and other strings. After this prints and loops back,
# program should end.
    elif expression == 'end':
        print('Shutting down... ')
# If the user inputs something where the last digit is not a digit, and is
# not end, the program will notify them and repeat.
    else:
        print('Enter with only digits and operators!')

Upvotes: 0

Views: 3816

Answers (1)

CoffeeTableEspresso
CoffeeTableEspresso

Reputation: 2652

eval is probably what you want here. eval is mainly discouraged because it allows any users of your app to execute arbitrary code, which obviously leads to security vulnerabilities. However, since you're doing this for learning experience, not in a publicly released app, this isn't really a concern for you. Especially if you are just learning, I'd ignore this for now (definitely don't do this in a production app).

You'll want to do: eval(input('please enter a expression')), which allows you to execute an arbitrary expression.

In the article you link, they explain that eval takes two more optional parameters, that allow you to restrict what expressions can be executed by the eval.

He sets the second parameter to {"__builtins__":None} to restrict you from using any global functions (if it is set to {}, builtin functions like abs are still available).

He sets the third parameter to a dictionary of all functions he'd like to allow the user to execute, since he just restricted the user to not being able to run any global functions previously.

Upvotes: 1

Related Questions