Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ast.literal_eval('5 * 7') fail?

Why does the literal evaluation of 5 * 7 fail, while 5 + 7 doesn't?

import ast

print(ast.literal_eval('5 + 7'))
# -> 12

print(ast.literal_eval('5 * 7'))
# -> 
Traceback (most recent call last):
  ...
ValueError: malformed node or string: <_ast.BinOp object at ...>

The documentation doesn't explain this.

I found that problem after answering this question on SO: Getting the result of a string.

like image 831
Laurent LAPORTE Avatar asked Nov 14 '16 08:11

Laurent LAPORTE


People also ask

What does AST literal_eval do in Python?

ast. literal_eval() The ast module helps Python applications to process trees of the Python abstract syntax grammar. The literal_eval safely evaluate an expression node or a string containing a Python literal or container display.

How safe is AST literal_eval?

The ast. literal_eval method can safely evaluate strings containing Python values from unknown sources without us having to parse the values. However, complex expressions involving indexing or operators cannot be evaluated using this function.

What is malformed string?

If you see this error, it usually means the the client is not able to transform the string you wrote to the character set acceptable to the Firebird server. Here's a short explanation how this works: In your client program, you type in some text, which is then shown on the screen.


1 Answers

ast.literal_eval() accepts + in the evaluated data because 5+2j (complex number*) are valid literals. The same applies to -. To keep the code simple, no attempt is made to exclude + or - as a binary operators.

No other operators are allowed; the function is supposed to only accept literals, not expressions.

In other words, that 5 + 7 works is a bug, but one that is hard to fix without breaking support for constructing complex numbers. The implementation limits the use to operands that are numbers, unary + and -, or other binary operators (so you can't use these to concatenate lists or produce a set difference).

Also see several related Python bugtracker entries: #25335 ast.literal_eval fails to parse numbers with leading "+", #22525 ast.literal_eval() doesn't do what the documentation says and #4907 ast.literal_eval does not properly handled complex numbers


* Technically speaking, 2j is a valid literal; Python parses 5+2j as int(5) binop(+) complex(0, 2), and only later produces a complex(5, 2) object from the result, when actually executing the addition.

like image 197
Martijn Pieters Avatar answered Oct 26 '22 23:10

Martijn Pieters