eval() in Python
Overview
The eval() function in Python evaluates the provided expression and executes it if it is a valid Python statement. It accepts a string and evaluates it as a Python expression. A variable, a function call, or a mathematical expression can all be used in the expression.
Syntax of eval() in Python
where:
-
expression is the string containing the Python expression to be evaluated.
-
globals is an optional dictionary that specifies the global namespace. The default value is the global namespace of the module from which the eval() method is called.
-
locals is an optional dictionary that provides the local namespace. The default value is the local namespace of the frame in which the eval() method is invoked.
If the globals and locals parameters are not supplied, they default to the namespaces of the frame in which the eval() function is invoked.
Parameters of eval() in Python
The function eval in python takes the required argument - expression. Along with this, eval in python also takes 2 arguments that are not required, they're optional - globals and locals.
-
The expression argument :
This is a required argument in the eval function in python. This expression must be either a string or a compiled-code-based input. So this input in the form of the expression when supplied to the eval function is evaluated as a Python expression. We'll discuss this in detail in the coming section.
-
The globals argument :
This argument is optional. The values accepted in this argument, are dictionaries that provide a global namespace to eval() in python. Namespaces are essentially dictionaries that provide scope to objects in Python. These dictionaries map names to objects. So here, these globals in the parameter of eval in python are all the global names i.e. all those names that are currently available in your global scope or namespace, which means that they are accessible from anywhere in your code. Again, we'll get to examples in a while.
-
The locals argument :
Coming to the third argument, which is optional again - locals. This too will be in the form of a dictionary and will contain all the local names i.e. the names that are defined inside a function and can be accessed only inside that particular function. In the eval function in python, you obviously cannot add local variable names to this function since it has already been written, but you can pass a dictionary in the locals argument and this eval() function will treat those variable names as locals.
Return value of eval() in Python
The eval() method in Python returns the result of the expression that was evaluated. The kind of return value can be any of the following:
- Integer
- Float
- String
- Boolean
- List
- Dictionary
- Tuple
- None
The type of the expression that was evaluated determines the eval() function's return value. For example, if the expression evaluates to an integer, the eval() function will return an integer.
Exceptions of eval() in Python
Python's eval() method can throw the following exceptions:
- SyntaxError: This error is thrown when the expression provided to the eval() method is not a valid Python expression.
- NameError: This error is thrown when the expression provided to the eval() method refers to a variable that does not exist.
- TypeError: This error is thrown when the expression provided to the eval() method is not of the right type.
- ValueError: This error is thrown when the expression provided to the eval() method is invalid.
- SystemExit: This exception is thrown when the expression provided to the eval() method invokes the sys.exit() function.
Other exceptions that can be raised by the eval() method are ZeroDivisionError, IndexError, and KeyError. These exceptions are thrown when an error unique to the kind of expression being evaluated occurs in the expression given to the eval() method.
It is critical to utilise the eval() function with caution and only evaluate expressions that you are confident in. If you are unsure if an expression is acceptable to evaluate, avoid using the eval() method entirely.
Example of eval() in Python
Output:
What Is Eval In Python?
The eval() in python does exactly as its name suggests, it evaluates the expression that is passed to it as input. Now this input, as discussed can be in the format of a string or code-compiled input.
A string-based input looks like this - which is essentially the product of 5 and 9. This when passed as a string expression to the method - eval in python gives us 45, which is the product of the two numbers. To give a compiled-code-based input to eval in python, you are required to make use of the compile() function in python. This way, you can supply code objects to eval() in place of the strings we looked at earlier.
What can you evaluate using eval in python?
Mathematical expressions, user input for small function evaluations, or function calls.
Now when you input a string as input in the function, eval() in python first parses the expression that you gave, then compiles it into bytecode. It is then evaluated as a python expression and the result of that is returned. However, if you give it in the compiled-code format, it simply evaluates the code that is compiled and then returns the result of that evaluation.
Now that you know what eval() in Python does, let's look at some examples to see how it works, and how you can use it.
How to Use eval() in Python?
-
The most basic use of eval(), with the string input as expression:
Output :
-
Using compiled-code input: The working of compile() function is out of the scope of this article, refer to its official documentation.
Output :
Output:
-
Using the globals argument:
Output:
-
Making use of the third argument -locals: Here, we will pass the globals argument as an empty dictionary to show how we're using the local variables.
Output:
Note : An important point to note is that to pass the locals argument without any globals, you must explicitly supply globals as an empty dict.
Above were some examples of how you can make use of eval() in python, however, there are some important issues to discuss as well.
Vulnerability Issues With Eval
Say you're using the eval() function in Python to take user input. You have no idea what the user can input to the function since eval() in python can execute anything that it receives as input. The user can call dangerous functions in eval() or even expose certain hidden values that could pose a threat to security systems. Let's exploit it. Say you have a function that contains a secure key, or confidential data, or even a password as one of its variables. When you're taking user input for evaluation, the user might call this function containing confidential data and extract the information!
Take a look at this:
Let's say that the user inputs the string " let_me_in() " when you're asking for input. Here's the output :
It was so easy to extract the secure key, it just took one function call into the eval() function. We now need to prevent this from happening since this is a major security threat!
Making Eval Safe
To reduce the risk of this function, we have a workaround. As we saw previously, eval() in python has two parameters that take in dictionaries of variables (globals and locals) that are used to evaluate the expression given in the input, so that eval() can access these variables or functions. So to make the code secure, we're going to explicitly specify the variables that the function can make use of. If a variable is mentioned in the globals/locals dictionaries, only then the expression containing that variable can be parsed for evaluation. However, if the expression does not contain the variable, it will return an error.
Here's how we will do it:
Output:
Now let's try the let_me_in() function as input :
Now we're safe since the eval() function was not able to execute the let_me_in() function and give us the security key as this expression did not contain the variable present in the safe_dict. Unfortunately by applying restrictions using the globals and locals dicts all the security risks related to this function are not eliminated as the user will still have access to built-ins of python. We'll see later how to restrict those as well.
Uses Of Eval
The eval() function in Python can be used to evaluate a wide variety of expressions, including:
- Variables: eval("x") where x is a variable name
- Function Calls: eval("print('Hello, world!')")
- Mathematical Expressions: eval("2 + 3 * 4")
- Strings: eval("'Hello, world!'")
- Arbitrary Python Code: eval("import math; print(math.pi)"
The eval() function is a useful tool, but it also poses a security concern. This is due to the fact that the eval() method may be used to run any Python code. This implies that if an attacker injects malicious code into a string provided to the eval() method, they may be able to seize control of the programme.
Here are some of the uses of the eval() function:
- To evaluate mathematical expressions.
- To evaluate function calls.
- To evaluate strings.
- To evaluate arbitrary Python code.
It is critical to utilise the eval() function with caution and only evaluate expressions that you are confident in. If you are unsure if an expression is acceptable to evaluate, avoid using the eval() method entirely.
More Examples
We've discussed multiple examples, however, let's take a look at some more examples where we've given different kinds of input.
-
Passing a compound statement like if :
Output :
eval() in python only accepts expressions and not compound statements such as if, for, import, while class or def. They will raise a SyntaxError.
-
Usage of incomplete expressions / expressions parser cannot understand :
Both these conditions will result in a SyntaxError.
-
Supplying names that do not exist in the current global scope of the program :
Output :
Here, the name / variable c was passed to eval() in the globals dict, and eval() interpreted it as a global variable. However, since it was not declared in the program explicitly, python does not recognize the variable c.
-
Passing empty globals :
Output:
The function eval() does not have access to " a " because the globals parameter was passed as an empty dict.
-
Evaluating boolean expressions :
Output:
-
Evaluating general purpose expressions :
Output:
Practical Example To Demonstrate Use Of eval()
Let's take a short code example to demonstrate how you could make use of eval in your code. Say you want to create an application that calculates the perimeter and area of a square, and you want the user to input whether it wants the area of the square calculated or the perimeter. Here's how you can do it using eval() in python.
Output:
Making certain methods available
If you'd like to use some functions from a module that aren't available in eval(), you can do so in the following manner. Let's say you want to use the functions sqrt() and pow() from the math module :
Output:
Remember when we said that the globals dict maps names to objects? Here, the key is mapping the name sqrt to the function sqrt which exists in the math module dir(). So now if you would like to calculate expressions with the use of the sqrt() and pow() functions from the math module aside from the __builtins__, you can do so.
Restricting The Use Of Built-Ins
We were able to prevent the user from accessing certain functions, however there's another vulnerability a user could exploit. The eval() function comes with another built-in function __import__() which can provide access to the standard library of python and also to a third-party module that you might have installed!
We know that to use the math module, we need to add it's functions in the global dict. But what if we don't? Let's see how the user can still do it :
Output:
The user was easily able to access any module using the __import__() function. Now to prevent this, we must override the __builtins__ key in the globals dict like this :
Output:
We have prevented the use of built-ins, however not thoroughly and the risk of using eval() still remains.
Conclusion
- Eval() in python is a function used to evaluate mathematical expressions, functions etc.
- Syntax : eval(expression [, globals[, locals]]).
- The function returns the evaluated value.
- The expression parameter takes input in the form of string or compiled code.
- Eval() in python has vulnerability issues since it can be easily exploited. These risks can be reduced by restricting the globals and locals dict to only.
- The risk still remains due to built-ins which can be further removed by restricting the built-ins key.