Basics Intermediate Advanced
aialgorithmsapibest-practicescareercommunitydatabasesdata-sciencedata-structuresdata-vizdevopsdjangodockereditorsflaskfront-endgamedevguimachine-learningnewsnumpyprojectspythonstdlibtestingtoolsweb-devweb-scraping
Recommended Course

Evaluate Expressions Dynamically With Python eval()
49m · 8 lessons

Python eval(): Evaluate Expressions Dynamically
Table of Contents
Recommended Course
Python’seval() allows you to evaluate arbitrary Pythonexpressions from a string-based orcompiled-code-based input. This function can be handy when you’re trying to dynamically evaluate Python expressions from any input that comes as astring or a compiled code object.
Although Python’seval() is an incredibly useful tool, the function has some important security implications that you should consider before using it. In this tutorial, you’ll learn howeval() works and how to use it safely and effectively in your Python programs.
In this tutorial, you’ll learn:
- How Python’s
eval()works - How to use
eval()todynamically evaluate arbitrary string-based or compiled-code-based input - How
eval()can make your code insecure and how to minimize the associatedsecurity risks
Additionally, you’ll learn how to use Python’seval() to code an application that interactively evaluates math expressions. With this example, you’ll apply everything you’ve learned abouteval() to a real-world problem. If you want to get the code for this application, then you can click on the box below:
Download the sample code:Click here to get the code you’ll use to learn about Python’s eval() in this tutorial.
Understanding Python’seval()
You can use the built-in Pythoneval() to dynamically evaluate expressions from a string-based or compiled-code-based input. If you pass in astring toeval(), then the function parses it, compiles it tobytecode, and evaluates it as a Python expression. But if you calleval() with a compiled code object, then the function performs just the evaluation step, which is quite convenient if you calleval() several times with the same input.
The signature of Python’seval() is defined as follows:
eval(expression[,globals[,locals]])The function takes a first argument, calledexpression, which holds the expression that you need to evaluate.eval() also takes two optional arguments:
globalslocals
In the next three sections, you’ll learn what these arguments are and howeval() uses them to evaluate Python expressions on the fly.
Note: You can also useexec() to dynamically execute Python code. The main difference betweeneval() andexec() is thateval() can only execute or evaluate expressions, whereasexec() can execute any piece of Python code.
The First Argument:expression
The first argument toeval() is calledexpression. It’s a required argument that holds thestring-based orcompiled-code-based input to the function. When you calleval(), the content ofexpression is evaluated as a Python expression. Check out the following examples that use string-based input:
>>>eval("2 ** 8")256>>>eval("1024 + 1024")2048>>>eval("sum([8, 16, 32])")56>>>x=100>>>eval("x * 2")200When you calleval() with a string as an argument, the function returns the value that results from evaluating the input string. By default,eval() has access to global names likex in the above example.
To evaluate a string-basedexpression, Python’seval() runs the following steps:
- Parse
expression - Compile it to bytecode
- Evaluate it as a Python expression
- Return the result of the evaluation
The nameexpression for the first argument toeval() highlights that the function works only with expressions and not withcompound statements. ThePython documentation definesexpression as follows:
expression
A piece of syntax which can be evaluated to some value. In other words, an expression is an accumulation of expression elements like literals, names, attribute access, operators or function calls which all return a value. In contrast to many other languages, not all language constructs are expressions. There are also statements which cannot be used as expressions, such as
while. Assignments are also statements, not expressions. (Source)
On the other hand, a Pythonstatement has the following definition:
statement
A statement is part of a suite (a “block” of code). A statement is either an expression or one of several constructs with a keyword, such as
if,whileorfor. (Source)
If you try to pass a compound statement toeval(), then you’ll get aSyntaxError. Take a look at the following example in which you try to execute anif statement usingeval():
>>>x=100>>>eval("if x: print(x)")Traceback (most recent call last): File"<stdin>", line1, in<module> File"<string>", line1ifx:print(x)^SyntaxError:invalid syntaxIf you try to evaluate a compound statement using Python’seval(), then you’ll get aSyntaxError like in the abovetraceback. That’s becauseeval() only accepts expressions. Any other statement, such asif,for,while,import,def, orclass, will raise an error.
Note: Afor loop is a compound statement, but theforkeyword can also be used incomprehensions, which are considered expressions. You can useeval() to evaluate comprehensions even though they use thefor keyword.
Assignment operations aren’t allowed witheval() either:
>>>eval("pi = 3.1416")Traceback (most recent call last): File"<stdin>", line1, in<module> File"<string>", line1pi=3.1416^SyntaxError:invalid syntaxIf you try to pass an assignment operation as an argument to Python’seval(), then you’ll get aSyntaxError. Assignment operations are statements rather than expressions, and statements aren’t allowed witheval().
You’ll also get aSyntaxError any time the parser doesn’t understand the input expression. Take a look at the following example in which you try to evaluate an expression that violates Python syntax:
>>># Incomplete expression>>>eval("5 + 7 *")Traceback (most recent call last): File"<input>", line1, in<module>eval("5 + 7 *") File"<string>", line15+7*^SyntaxError:unexpected EOF while parsingYou can’t pass an expression toeval() that violates Python syntax. In the above example, you try to evaluate an incomplete expression ("5 + 7 *") and get aSyntaxError because the parser doesn’t understand the syntax of the expression.
You can also passcompiled code objects to Python’seval(). To compile the code that you’re going to pass toeval(), you can usecompile(). This is a built-in function that can compile an input string into acode object or anAST object so that you can evaluate it witheval().
The details of how to usecompile() are beyond the scope of this tutorial, but here’s a quick look at its first three required arguments:
sourceholds the source code that you want to compile. This argument accepts normal strings,byte strings, and AST objects.filenamegives the file from which the code was read. If you’re going to use a string-based input, then the value for this argument should be"<string>".modespecifies which kind of compiled code you want to get. If you want to process the compiled code witheval(), then this argument should be set to"eval".
Note: For more information oncompile(), check out theofficial documentation.
You can usecompile() to supply code objects toeval() instead of normal strings. Check out the following examples:
>>># Arithmetic operations>>>code=compile("5 + 4","<string>","eval")>>>eval(code)9>>>code=compile("(5 + 7) * 2","<string>","eval")>>>eval(code)24>>>importmath>>># Volume of a sphere>>>code=compile("4 / 3 * math.pi * math.pow(25, 3)","<string>","eval")>>>eval(code)65449.84694978735If you usecompile() to compile the expressions that you’re going to pass toeval(), theneval() goes through the following steps:
- Evaluate the compiled code
- Return the result of the evaluation
If you call Python’seval() using a compiled-code-based input, then the function performs the evaluation step and immediately returns the result. This can be handy when you need to evaluate the same expression multiple times. In this case, it’s best to precompile the expression and reuse the resulting bytecode on subsequent calls toeval().
If you compile the input expression beforehand, then successive calls toeval() will run faster because you won’t be repeating theparsing andcompiling steps. Unneeded repetitions can lead to high CPU times and excessive memory consumption if you’re evaluating complex expressions.
The Second Argument:globals
The second argument toeval() is calledglobals. It’s optional and holds adictionary that provides a globalnamespace toeval(). Withglobals, you can telleval() which global names to use while evaluatingexpression.
Global names are all those names that are available in yourcurrent global scope or namespace. You can access them from anywhere in your code.
All the names passed toglobals in a dictionary will be available toeval() at execution time. Check out the following example, which shows how to use a custom dictionary to supply a globalnamespace toeval():
>>>x=100# A global variable>>>eval("x + 100",{"x":x})200>>>y=200# Another global variable>>>eval("x + y",{"x":x})Traceback (most recent call last): File"<stdin>", line1, in<module> File"<string>", line1, in<module>NameError:name 'y' is not definedIf you supply a custom dictionary to theglobals argument ofeval(), theneval() will take only those names as globals. Any global names defined outside of this custom dictionary won’t be accessible from insideeval(). That’s why Python raises aNameError when you try to accessy in the above code: The dictionary passed toglobals doesn’t includey.
You can insert names intoglobals by listing them in your dictionary, and then those names will be available during the evaluation process. For example, if you inserty intoglobals, then the evaluation of"x + y" in the above example will work as expected:
>>>eval("x + y",{"x":x,"y":y})300Since you addy to your customglobals dictionary, the evaluation of"x + y" is successful and you get the expected return value of300.
You can also supply names that don’t exist in your current global scope. For this to work, you need to supply a concrete value for each name.eval() will interpret these names as global names when running:
>>>eval("x + y + z",{"x":x,"y":y,"z":300})600>>>zTraceback (most recent call last): File"<stdin>", line1, in<module>NameError:name 'z' is not definedEven thoughz isn’t defined in your current global scope, thevariable is present inglobals with a value of300. In this case,eval() has access toz as though it were aglobal variable.
The mechanism behindglobals is quite flexible. You can pass any visible variable (global,local, ornonlocal) toglobals. You can also pass custom key-value pairs like"z": 300 in the above example.eval() will treat all of them as global variables.
An important point regardingglobals is that if you supply a custom dictionary to it that doesn’t contain a value for the key"__builtins__", then a reference to the dictionary ofbuiltins will be automatically inserted under"__builtins__" beforeexpression gets parsed. This ensures thateval() will have full access to all of Python’s built-in names when evaluatingexpression.
The following examples show that even though you supply an empty dictionary toglobals, the call toeval() will still have access to Python’s built-in names:
>>>eval("sum([2, 2, 2])",{})6>>>eval("min([1, 2, 3])",{})1>>>eval("pow(10, 2)",{})100In the above code, you supply an empty dictionary ({}) toglobals. Since that dictionary doesn’t contain a key called"__builtins__", Python automatically inserts one with a reference to the names inbuiltins. This way,eval() has full access to all of Python’s built-in names when it parsesexpression.
If you calleval() without passing a custom dictionary toglobals, then the argument will default to the dictionary returned byglobals() in the environment whereeval() is called:
>>>x=100# A global variable>>>y=200# Another global variable>>>eval("x + y")# Access both global variables300When you calleval() without supplying aglobals argument, the function evaluatesexpression using the dictionary returned byglobals() as its global namespace. So, in the above example, you can freely accessx andy because they’re global variables included in your currentglobal scope.
The Third Argument:locals
Python’seval() takes a third argument calledlocals. This is another optional argument that holds a dictionary. In this case, the dictionary contains the variables thateval() uses as local names when evaluatingexpression.
Local names are those names (variables,functions,classes, and so on) that you define inside a given function. Local names are visible only from inside the enclosing function. You define these kinds of names when you’re writing a function.
Sinceeval() is already written, you can’t add local names to its code orlocal scope. However, you can pass a dictionary tolocals, andeval() will treat those names as local names:
>>>eval("x + 100",{},{"x":100})200>>>eval("x + y",{},{"x":100})Traceback (most recent call last): File"<stdin>", line1, in<module> File"<string>", line1, in<module>NameError:name 'y' is not definedThe second dictionary in the first call toeval() holds the variablex. This variable is interpreted byeval() as a local variable. In other words, it’s seen as a variable defined in the body ofeval().
You can usex inexpression, andeval() will have access to it. In contrast, if you try to usey, then you’ll get aNameError becausey isn’t defined in either theglobals namespace or thelocals namespace.
Like withglobals, you can pass any visible variable (global, local, or nonlocal) tolocals. You can also pass custom key-value pairs like"x": 100 in the above example.eval() will treat all of them as local variables.
Note that to supply a dictionary tolocals, you first need to supply a dictionary toglobals. It’s not possible to use keyword arguments witheval():
>>>eval("x + 100",locals={"x":100})Traceback (most recent call last): File"<stdin>", line1, in<module>TypeError:eval() takes no keyword argumentsIf you try to use keyword arguments when callingeval(), then you’ll get aTypeError explaining thateval() takes no keyword arguments. So, you need to supply aglobals dictionary before you can supply alocals dictionary.
If you don’t pass a dictionary tolocals, then it defaults to the dictionary passed toglobals. Here’s an example in which you pass an empty dictionary toglobals and nothing tolocals:
>>>x=100>>>eval("x + 100",{})Traceback (most recent call last): File"<stdin>", line1, in<module> File"<string>", line1, in<module>NameError:name 'x' is not definedGiven that you don’t provide a custom dictionary tolocals, the argument defaults to the dictionary passed toglobals. In this case,eval() doesn’t have access tox becauseglobals holds an empty dictionary.
The main practical difference betweenglobals andlocals is that Python will automatically insert a"__builtins__" key intoglobals if that key doesn’t already exist. This happens whether or not you supply a custom dictionary toglobals. On the other hand, if you supply a custom dictionary tolocals, then that dictionary will remain unchanged during the execution ofeval().
Evaluating Expressions With Python’seval()
You can use Python’seval() to evaluate any kind of Python expression but not Python statements such as keyword-based compound statements or assignment statements.
eval() can be handy when you need to dynamically evaluate expressions and using other Python techniques or tools would considerably increase your development time and effort. In this section, you’ll learn how you can use Python’seval() to evaluate Boolean, math, and general-purpose Python expressions.
Boolean Expressions
Boolean expressions are Python expressions that return a truth value (True orFalse) when the interpreter evaluates them. They’re commonly used inif statements to check if some condition is true or false. Since Boolean expressions aren’t compound statements, you can useeval() to evaluate them:
>>>x=100>>>y=100>>>eval("x != y")False>>>eval("x < 200 and y > 100")False>>>eval("x is y")True>>>eval("x in {50, 100, 150, 200}")TrueYou can useeval() with Boolean expressions that use any of the following Python operators:
- Value comparison operators:
<,>,<=,>=,==,!= - Logical (Boolean) operators:
and,or,not - Membership test operators:
in,not in - Identity operators:
is,is not
In all cases, the function returns the truth value of the expression that you’re evaluating.
Now, you may be thinking, why should I useeval() instead of using the Boolean expression directly? Well, suppose you need to implement a conditional statement, but you want to change the condition on the fly:
>>>deffunc(a,b,condition):...ifeval(condition):...returna+b...returna-b...>>>func(2,4,"a > b")-2>>>func(2,4,"a < b")6>>>func(2,2,"a is b")4Insidefunc(), you useeval() to evaluate the suppliedcondition and return eithera + b ora - b according to the result of the evaluation. You use just a few different conditions in the above example, but you could use any number of others provided that you stick with the namesa andb that you defined infunc().
Now imagine how you would implement something like this without the use of Python’seval(). Would that take less code and time? No way!
Math Expressions
One common use case of Python’seval() is to evaluate math expressions from a string-based input. For example, if you want to create aPython calculator, then you can useeval() to evaluate theuser’s input and return the result of the calculations.
The following examples show how you can useeval() along withmath to perform math operations:
>>># Arithmetic operations>>>eval("5 + 7")12>>>eval("5 * 7")35>>>eval("5 ** 7")78125>>>eval("(5 + 7) / 2")6.0>>>importmath>>># Area of a circle>>>eval("math.pi * pow(25, 2)")1963.4954084936207>>># Volume of a sphere>>>eval("4 / 3 * math.pi * math.pow(25, 3)")65449.84694978735>>># Hypotenuse of a right triangle>>>eval("math.sqrt(math.pow(10, 2) + math.pow(15, 2))")18.027756377319946When you useeval() to evaluate math expressions, you can pass in expressions of any kind or complexity.eval() will parse them, evaluate them and, if everything is okay, give you the expected result.
General-Purpose Expressions
So far, you’ve learned how to useeval() with Boolean and math expressions. However, you can useeval() with more complex Python expressions that incorporate function calls, object creation, attribute access,comprehensions, and so on.
For example, you can call a built-in function or one that you’ve imported with a standard or third-party module:
>>># Run the echo command>>>importsubprocess>>>eval("subprocess.getoutput('echo Hello, World')")'Hello, World'>>># Launch Firefox (if available)>>>eval("subprocess.getoutput('firefox')")''In this example, you use Python’seval() to execute a few system commands. As you can imagine, you can do aton of useful things with this feature. However,eval() can also expose you to serious security risks, like allowing a malicious user to run system commands or any arbitrary piece of code in your machine.
In the next section, you’ll look at ways to address some of the security risks associated with eval().
Minimizing the Security Issues ofeval()
Although it has an almost unlimited number of uses, Python’seval() also has importantsecurity implications.eval() is considered insecure because it allows you (or your users) to dynamically execute arbitrary Python code.
This is considered bad programming practice because the code that you’re reading (or writing) isnot the code that you’ll execute. If you’re planning to useeval() to evaluate input from a user or any other external source, then you won’t know for sure what code is going to be executed. That’s a serious security risk if your application runs in the wrong hands.
For this reason, good programming practices generally recommend against usingeval(). But if you choose to use the function anyway, then the rule of thumb is tonever ever use it withuntrusted input. The tricky part of this rule is figuring out which kinds of input you can trust.
As an example of how usingeval() irresponsibly can make your code insecure, suppose you want to build an online service for evaluating arbitrary Python expressions. Your user will introduce expressions and then click theRun button. The application will get the user’s input and pass it toeval() for evaluation.
This application will run on your personal server. Yes, the same server where you have all those valuable files. If you’re running a Linux box and the application’s process has the right permissions, then a malicious user could introduce a dangerous string like the following:
"__import__('subprocess').getoutput('rm –rf *')"The above code would delete all the files in the application’s current directory. That would be awful, wouldn’t it?
Note:__import__() is a built-in function that takes a module name as a string and returns a reference to the module object.__import__() is a function, which is totally different from animport statement. You can’t evaluate animport statement usingeval().
When the input is untrusted, there’s no completely effective way to avoid the security risks associated witheval(). However, you can minimize your risk by restricting the execution environment ofeval(). You’ll learn a few techniques for doing so in the following sections.
Restrictingglobals andlocals
You can restrict the execution environment ofeval() by passing custom dictionaries to theglobals andlocals arguments. For example, you can pass empty dictionaries to both arguments to preventeval() from accessing names in the caller’scurrent scope or namespace:
>>># Avoid access to names in the caller's current scope>>>x=100>>>eval("x * 5",{},{})Traceback (most recent call last): File"<stdin>", line1, in<module> File"<string>", line1, in<module>NameError:name 'x' is not definedIf you pass empty dictionaries ({}) toglobals andlocals, theneval() won’t find the namex in either its global namespace or its local namespace when evaluating the string"x * 5". As a result,eval() will throw aNameError.
Unfortunately, restricting theglobals andlocals arguments like this doesn’t eliminate all the security risks associated with the use of Python’seval(), because you can still access all of Python’s built-in names.
Restricting the Use of Built-In Names
As you saw earlier, Python’seval() automatically inserts a reference to the dictionary ofbuiltins intoglobals before parsingexpression. A malicious user could exploit this behavior by using the built-in function__import__() to get access to the standard library and any third-party module that you’ve installed on your system.
The following examples show that you can use any built-in function and any standard module likemath orsubprocess even after you’ve restrictedglobals andlocals:
>>>eval("sum([5, 5, 5])",{},{})15>>>eval("__import__('math').sqrt(25)",{},{})5.0>>>eval("__import__('subprocess').getoutput('echo Hello, World')",{},{})'Hello, World'Even though you restrictglobals andlocals using empty dictionaries, you can still use any built-in function like you did withsum() and__import__() in the above code.
You can use__import__() to import any standard or third-party module just like you did above withmath andsubprocess. With this technique, you can access any function or class defined inmath,subprocess, or any other module. Now imagine what a malicious user could do to your system usingsubprocess or any other powerful module in the standard library.
To minimize this risk, you can restrict access to Python’s built-in functions by overriding the"__builtins__" key inglobals. Good practice recommends using a custom dictionary containing the key-value pair"__builtins__": {}. Check out the following example:
>>>eval("__import__('math').sqrt(25)",{"__builtins__":{}},{})Traceback (most recent call last): File"<stdin>", line1, in<module> File"<string>", line1, in<module>NameError:name '__import__' is not definedIf you pass a dictionary containing the key-value pair"__builtins__": {} toglobals, theneval() won’t have direct access to Python’s built-in functions like__import__(). However, as you’ll see in the next section, this approach still doesn’t makeeval() completely secure.
Restricting Names in the Input
Even though you can restrict the execution environment of Python’seval() using customglobals andlocals dictionaries, the function will still be vulnerable to a few fancy tricks. For example, you can access the classobject using atype literal like"",[],{}, or() along with some special attributes:
>>>"".__class__.__base__<class 'object'>>>>[].__class__.__base__<class 'object'>>>>{}.__class__.__base__<class 'object'>>>>().__class__.__base__<class 'object'>Once you have access toobject, you can use aspecial method,.__subclasses__(), to get access to all of the classes that inherit fromobject. Here’s how it works:
>>>forsub_classin().__class__.__base__.__subclasses__():...print(sub_class.__name__)...typeweakrefweakcallableproxyweakproxyint...This code willprint a large list of classes to your screen. Some of these classes are quite powerful and can be extremely dangerous in the wrong hands. This opens up another important security hole that you can’t close by simply restricting the execution environment ofeval():
>>>input_string="""[... c for c in ().__class__.__base__.__subclasses__()... if c.__name__ == "range"...][0](10)""">>>list(eval(input_string,{"__builtins__":{}},{}))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]The list comprehension in the above code filters the classes that inherit fromobject to return alist containing the classrange. The first index ([0]) returns the classrange. Once you have access torange, you call it to generate arange object. Then you calllist() on therange object to generate a list of ten integers.
In this example, you userange to illustrate a security hole ineval(). Now imagine what a malicious user could do if your system exposed classes likesubprocess.Popen.
Note: For a deeper dive into the vulnerabilities ofeval(), check out Ned Batchelder’sarticle,Eval really is dangerous.
A possible solution to this vulnerability is to restrict the use of names in the input, either to a bunch ofsafe names or tono names at all. To implement this technique, you need to go through the following steps:
- Create a dictionary containing the names that you want to use with
eval(). - Compile the input string to bytecode using
compile()in mode"eval". - Check
.co_nameson the bytecode object to make sure it contains only allowed names. - Raise a
NameErrorif the user tries to enter a name that’s not allowed.
Take a look at the following function in which you implement all these steps:
>>>defeval_expression(input_string):...# Step 1...allowed_names={"sum":sum}...# Step 2...code=compile(input_string,"<string>","eval")...# Step 3...fornameincode.co_names:...ifnamenotinallowed_names:...# Step 4...raiseNameError(f"Use of{name} not allowed")...returneval(code,{"__builtins__":{}},allowed_names)Ineval_expression(), you implement all of the steps you saw before. This function restricts the names that you can use witheval() to only those names in the dictionaryallowed_names. To do this, the function uses.co_names, which is an attribute of a code object that returns atuple containing the names in the code object.
The following examples show howeval_expression() works in practice:
>>>eval_expression("3 + 4 * 5 + 25 / 2")35.5>>>eval_expression("sum([1, 2, 3])")6>>>eval_expression("len([1, 2, 3])")Traceback (most recent call last): File"<stdin>", line1, in<module> File"<stdin>", line10, ineval_expressionNameError:Use of len not allowed>>>eval_expression("pow(10, 2)")Traceback (most recent call last): File"<stdin>", line1, in<module> File"<stdin>", line10, ineval_expressionNameError:Use of pow not allowedIf you calleval_expression() to evaluate arithmetic operations, or if you use expressions that include allowed names, then you’ll get the expected result. Otherwise, you’ll get aNameError. In the above examples, the only name you’ve allowed issum(). Other names likelen() andpow() are not allowed, so the function raises aNameError when you try to use them.
If you want to completely disallow the use of names, then you can rewriteeval_expression() as follows:
>>>defeval_expression(input_string):...code=compile(input_string,"<string>","eval")...ifcode.co_names:...raiseNameError(f"Use of names not allowed")...returneval(code,{"__builtins__":{}},{})...>>>eval_expression("3 + 4 * 5 + 25 / 2")35.5>>>eval_expression("sum([1, 2, 3])")Traceback (most recent call last): File"<stdin>", line1, in<module> File"<stdin>", line4, ineval_expressionNameError:Use of names not allowedNow your function doesn’t allowany names in the input string. To accomplish this, you check for names in.co_names and raise aNameError if one is found. Otherwise, you evaluateinput_string and return the result of the evaluation. In this case, you use an empty dictionary to restrictlocals as well.
You can use this technique to minimize the security issues ofeval() and strengthen your armor against malicious attacks.
Restricting the Input to Only Literals
A common use case for Python’seval() is to evaluate strings that contain standard Python literals and turn them into concrete objects.
The standard library provides a function calledliteral_eval() that can help achieve this goal. The function doesn’t support operators, but it does supportlists,tuples,numbers, strings, and so on:
>>>fromastimportliteral_eval>>># Evaluating literals>>>literal_eval("15.02")15.02>>>literal_eval("[1, 15]")[1, 15]>>>literal_eval("(1, 15)")(1, 15)>>>literal_eval("{'one': 1, 'two': 2}"){'one': 1, 'two': 2}>>># Trying to evaluate an expression>>>literal_eval("sum([1, 15]) + 5 + 8 * 2")Traceback (most recent call last):...ValueError:malformed node or string: <_ast.BinOp object at 0x7faedecd7668>Notice thatliteral_eval() only works with standard type literals. It doesn’t support the use of operators or names. If you try to feed an expression toliteral_eval(), then you’ll get aValueError. This function can also help you minimize the security risks associated with the use of Python’seval().
Using Python’seval() Withinput()
InPython 3.x, the built-ininput() reads the user input at the command line, converts it to a string, strips the trailing newline, and returns the result to the caller. Since the result ofinput() is a string, you can feed it toeval() and evaluate it as a Python expression:
>>>eval(input("Enter a math expression: "))Enter a math expression: 15 * 230>>>eval(input("Enter a math expression: "))Enter a math expression: 5 + 813You can wrap Python’seval() aroundinput() to automatically evaluate the user’s input. This is a common use case foreval() because it emulates the behavior ofinput() in Python 2.x, in whichinput() evaluates the user’s input as a Python expression and returns the result.
This behavior ofinput() in Python 2.x was changed in Python 3.x because of its security implications.
Building a Math Expressions Evaluator
So far, you’ve learned how Python’seval() works and how to use it in practice. You’ve also learned thateval() has important security implications and that it’s generally considered good practice to avoid the use ofeval() in your code. However, there are some situations in which Python’seval() can save you a lot of time and effort.
In this section, you’re going to code an application to evaluate math expressions on the fly. If you wanted to solve this problem without usingeval(), then you’d need to go through the following steps:
- Parse the input expression.
- Change the expression’s components into Python objects (numbers, operators, functions, and so on).
- Combine everything into an expression.
- Confirm that the expression is valid in Python.
- Evaluate the final expression and return the result.
That would be a lot of work considering the wide variety of possible expressions that Python can process and evaluate. Fortunately, you can useeval() to solve this problem, and you’ve already learned several techniques to reduce the associated security risks.
You can get the source code for the application that you’re going to build in this section by clicking on the box below:
Download the sample code:Click here to get the code you’ll use to learn about Python’s eval() in this tutorial.
First, fire up your favorite code editor. Create a newPython script calledmathrepl.py, and then add the following code:
1importmath 2 3__version__="1.0" 4 5ALLOWED_NAMES={ 6k:vfork,vinmath.__dict__.items()ifnotk.startswith("__") 7} 8 9PS1="mr>>"1011WELCOME=f"""12MathREPL{__version__}, your Python math expressions evaluator!13Enter a valid math expression after the prompt "{PS1}".14Type "help" for more information.15Type "quit" or "exit" to exit.16"""1718USAGE=f"""19Usage:20Build math expressions using numeric values and operators.21Use any of the following functions and constants:2223{', '.join(ALLOWED_NAMES.keys())}24"""In this piece of code, you first import Python’smath module. This module will allow you to perform math operations using predefined functions and constants. The constantALLOWED_NAMES holds a dictionary containing the non-special names inmath. This way, you’ll be able to use them witheval().
You also define three morestring constants. You’ll use them as the user interface to your script and you’ll print them to the screen as needed.
Now you’re ready to code the core functionality of your application. In this case, you want to code a function that receives math expressions as input and returns their result. To do this, you write a function calledevaluate():
26defevaluate(expression):27"""Evaluate a math expression."""28# Compile the expression29code=compile(expression,"<string>","eval")3031# Validate allowed names32fornameincode.co_names:33ifnamenotinALLOWED_NAMES:34raiseNameError(f"The use of '{name}' is not allowed")3536returneval(code,{"__builtins__":{}},ALLOWED_NAMES)Here’s how the function works:
Inline
26, you defineevaluate(). This function takes the stringexpressionas an argument and returns afloat that represents the result of evaluating the string as a math expression.Inline
29, you usecompile()to turn the input stringexpressioninto compiled Python code. The compiling operation will raise aSyntaxErrorif the user enters an invalid expression.Inline
32, you start aforloop to inspect the names contained inexpressionand confirm that they can be used in the final expression. If the user provides a name that is not in the list of allowed names, then you raise aNameError.Inline
36, you perform the actual evaluation of the math expression. Notice that you pass custom dictionaries toglobalsandlocalsas good practice recommends.ALLOWED_NAMESholds the functions and constants defined inmath.
Note: Since this application uses the functions defined inmath, you need to consider that some of these functions will raise aValueError when you call them with an invalid input value.
For example,math.sqrt(-10) would raise an error because thesquare root of-10 is undefined. Later on, you’ll see how to catch this error in your client code.
The use of custom values for theglobals andlocals parameters, along with the check of names inline33, allows you to minimize the security risks associated with the use ofeval().
Your math expression evaluator will be finished when you write its client code inmain(). In this function, you’ll define the program’s main loop and close the cycle of reading and evaluating the expressions that your user enters in the command line.
For this example, the application will:
- Print a welcome message to the user
- Show a prompt ready to read the user’s input
- Provide options to get usage instructions and to terminate the application
- Read the user’s math expression
- Evaluate the user’s math expression
- Print the result of the evaluation to the screen
Check out the following implementation ofmain():
38defmain():39"""Main loop: Read and evaluate user's input."""40print(WELCOME)41whileTrue:42# Read user's input43try:44expression=input(f"{PS1} ")45except(KeyboardInterrupt,EOFError):46raiseSystemExit()4748# Handle special commands49ifexpression.lower()=="help":50print(USAGE)51continue52ifexpression.lower()in{"quit","exit"}:53raiseSystemExit()5455# Evaluate the expression and handle errors56try:57result=evaluate(expression)58exceptSyntaxError:59# If the user enters an invalid expression60print("Invalid input expression syntax")61continue62except(NameError,ValueError)aserr:63# If the user tries to use a name that isn't allowed64# or an invalid value for a given math function65print(err)66continue6768# Print the result if no error occurs69print(f"The result is:{result}")7071if__name__=="__main__":72main()Insidemain(), you first print theWELCOME message. Then you read the user’s input in atry statement to catchKeyboardInterrupt andEOFError. If either of these exceptions occur, then you terminate the application.
If the user enters thehelp option, then the application shows yourUSAGE guide. Likewise, if the user entersquit orexit, then the application terminates.
Finally, you useevaluate() to evaluate the user’s math expression, and then you print the result to the screen. It’s important to note that a call toevaluate() can raise the following exceptions:
SyntaxError: This happens when the user enters an expression that doesn’t follow Python syntax.NameError: This happens when the user tries to use a name (function, class, or attribute) that isn’t allowed.ValueError: This happens when the user tries to use a value that isn’t allowed as an input to a given function inmath.
Notice that inmain(), you catch all of these exceptions and print messages to the user accordingly. This will allow the user to review the expression, fix the problem, and run the program again.
That’s it! You’ve built a math expression evaluator in about seventy lines of code using Python’seval(). Torun the application, open your system’s command line and type the following command:
$python3mathrepl.pyThis command will launch the math expression evaluator’scommand-line interface (CLI). You’ll see something like this on your screen:
MathREPL 1.0, your Python math expressions evaluator!Enter a valid math expression after the prompt "mr>>".Type "help" for more information.Type "quit" or "exit" to exit.mr>>Once you’re there, you can enter and evaluate any math expression. For example, type the following expressions:
mr>> 25 * 2The result is: 50mr>> sqrt(25)The result is: 5.0mr>> piThe result is: 3.141592653589793If you enter a valid math expression, then the application evaluates it and prints the result to your screen. If there are any problems with your expressions, then the application will tell you:
mr>> 5 * (25 + 4Invalid input expression syntaxmr>> sum([1, 2, 3, 4, 5])The use of 'sum' is not allowedmr>> sqrt(-15)math domain errormr>> factorial(-15)factorial() not defined for negative valuesIn the first example, you miss the closing parentheses, so you get a message telling you that the syntax is incorrect. Then you callsum(), which isn’t allowed, and you get an explanatory error message. Finally, you call amath function with an invalid input value, and the application generates a message identifying the problem in your input.
There you have it—your math expressions evaluator is ready! Feel free to add some extra features. A few ideas to get you started include enlarging the dictionary of allowed names and adding more elaborate warning messages. Give it a shot and let us know in the comments how it goes.
Conclusion
You can use Python’seval() to evaluate Pythonexpressions from a string-based or code-based input. This built-in function can be useful when you’re trying to evaluate Python expressions on the fly and you want to avoid the hassle of creating your own expressions evaluator from scratch.
In this tutorial, you’ve learned howeval() works and how to use it safely and effectively to evaluate arbitrary Python expressions.
You’re now able to:
- Use Python’s
eval()to dynamicallyevaluate basic Python expressions - Run more complex statements likefunction calls,object creation, andattribute access using
eval() - Minimize thesecurity risks associated with the use of Python’s
eval()
Additionally, you’ve coded an application that useseval() to interactively evaluate math expressions using acommand-line interface. You can download the application’s code by clicking on the link below:
Download the sample code:Click here to get the code you’ll use to learn about Python’s eval() in this tutorial.
Recommended Course
🐍 Python Tricks 💌
Get a short & sweetPython Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

AboutLeodanis Pozo Ramos
Leodanis is a self-taught Python developer, educator, and technical writer with over 10 years of experience.
» More about LeodanisMasterReal-World Python Skills With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
MasterReal-World Python Skills
With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
What Do You Think?
What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.
Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students.Get tips for asking good questions andget answers to common questions in our support portal.
Looking for a real-time conversation? Visit theReal Python Community Chat or join the next“Office Hours” Live Q&A Session. Happy Pythoning!
Keep Learning
Keep reading Real Python by creating a free account or signing in:
Already have an account?Sign-In





