We often need a way to evaluate certain Python expressions inside our python code without getting into much trouble with malicious expressions. We can use ast.literal_eval() in our python code to achieve those things.
What is ast.literal_eval()?
“ast” class’ full form is Abstract Syntax Tree. It contains ast.literal_eval() function. It is used to evaluate trees of the Python abstract syntax grammar. Abstract syntax changes with each python release. Custom parsers are one use case of ast.literal_eval() function.
ast.literal_eval() acceptable parameters
We use the ast.literal_eval() to securely evaluate a Python string containing a literal or container display.
Only the following Python literal structures are permissible in the string passed to the ast.lietral_eval() such as:-
- Strings.
- Tuples.
- Dictionaries.
- Sets
- Lists
- Booleans
- Bytes
- Numbers
- None
We can only pass a string as an argument to ast.literal_eval() containing expression.
Its syntax is as follows:-
ast.literal_eval(a Python expression following above steps)
Why use ast.literal_eval()
Without us having to put effort into interpreting the contents, the ast.literal eval function securely evaluates strings containing Python values from malicious sources.
However, this function cannot evaluate complicated expressions including indexing or operators.
It throws an error if the input is not one of the known data types, as we saw above.
Some examples
There are various examples of how to use ast.literal_eval().
Let us see some examples:
In this example, we will be converting the string representation of a list into a list using ast.literal_eval():-
from ast import literal_eval
str = "['a','b','c','d']"
list = literal_eval(str)
print(list)
print(type(list))
The above code will have output as:-
We often compare eval() and ast.literal_eval(). They are not completely identical, even though they appear to do the same things as each other.
The ast.literal_eval() takes a bit more precaution and safeguards against any mishappening which can happen upon evaluating a python expression.
Let us see an example to understand better what I am talking about:-
The Ast.literal eval() will produce an error if you pass it
ast.literal_eval(__import ('os').system('rm -rf /a-path-you-really-care-about')
yet eval() will cheerfully erase your files.
Use ast.literal eval because it appears you only allow the user to enter a normal dictionary ().
The eval evaluates any expression and will begin deleting the files as soon as we implement the above expression. The ast.literal_eval() completes the above request without any headache.
The reason behind the restricted use of ast.literal_eval()
ast.literal_eval() function can act as a viable substitute for eval() since it is safe as compared to eval().
Additionally, parsing more complex expressions like multiplication, list/dictionary indexing, and function calls are ineffective due to the safety mechanisms built into the language.
Safety comes at a cost.
Python’s eval() vs ast.literal_eval()
Here we will be comparing python’s eval() and ast.literal_eval()
eval() | literal_eval() |
---|---|
It doesn’t have any restrictions. | It only accepts a portion of Python’s syntax as legitimate |
It evaluates the code as soon as the function is called; we will have to evaluate its safety by ourselves. | If the input is not a valid Python datatype, an exception is thrown, and the function is not performed. |
It is really powerful, but it can be quite hazardous if we allow strings to be evaluated from untrusted input. | Safely evaluate an expression node or a string containing a Python literal or container display. |
Syntax:-eval(expression) | Syntax:-ast.literal_eval(node_or_string) |
What is its alternative?
The eval() is one of its alternatives, but it is not recommended as it is very powerful and can be dangerous.
The ast.parse() is another of its alternative, which can take a string as its input, parses, and then evaluates.
ast.parse(string, mode = 'eval')
What does malformed string mean?
The error “malformed string” occurs when the string passed for evaluation is incomprehensible.
E.g., the below snippet will produce an error, namely “malformed string”, as we have forgotten to represent a,b,c, and as separate strings.
ast.literal_eval("[a,b,c,d]")
The following code corrects the above problem:-
ast.literal_eval("["a","b","c","d"]")
Using ast.literal_eval() with pandas
Using AST’s literal_eval() function, we can handle more complex kinds of data in which a specific column may include an array of values rather than standard data types such as Strings, Integers, Timestamps, and so on.
ast.literal_eval() vs json.loads()
The json.loads() function parses a valid JSON string. It converts it to a Python dictionary. ast.literal_eval evaluates legitimate python expressions. ast.literal_eval() will work in the places where json.loads() won’t work.
ast.literal_eval() unexpected EOF while parsing
ast uses compile to convert the source string (which must be an expression) into an AST. If the source string is not a valid expression (for example, an empty string), compile will throw a SyntaxError “unexpected EOF while parsing”.
The below code throws a syntax error
ast.literal_eval(' ')
FAQs
Compilers frequently employ binary trees to create an interim visualization of the code that has not been completely compiled, known as an abstract syntax tree.
Yes, they can be called data structures; they are widely used in compilers.
Yes, a binary tree is used to build an AST.
Yes, it is safe and can be used over untrusted code. ast.literal_eval() firstly parses and then evaluates whatever is needed.