为什么ast.literal_eval(' 5 * 7')会失败?

时间:2016-11-14 08:19:21

标签: python eval abstract-syntax-tree

为什么5 * 7的字面值评估失败,而5 + 7没有?

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 ...>

documentation并没有解释这一点。

我在SO上回答了这个问题后发现了这个问题:Getting the result of a string

2 个答案:

答案 0 :(得分:13)

npm install --save @types/google-maps 在评估数据中接受ast.literal_eval(),因为+(复数 * )是有效的文字。这同样适用于5+2j。为了简化代码,不会尝试将-+排除为二元运算符。

不允许其他运营商;该函数假设只接受文字,而不是表达。

换句话说,-工作是一个错误,但在不破坏对构造复数的支持的情况下难以修复。 implementation限制对数字,一元5 + 7+或其他二元运算符的操作数的使用(因此您不能使用它们来连接列表或产生集合差异)。

另请参阅几个相关的Python bugtracker条目:#25335 ast.literal_eval fails to parse numbers with leading "+"#22525 ast.literal_eval() doesn't do what the documentation says#4907 ast.literal_eval does not properly handled complex numbers

* 从技术上讲,-是一个有效的文字; Python将2j解析为5+2j,并且只有在实际执行添加时才会从结果中生成int(5) binop(+) complex(0, 2)对象。

答案 1 :(得分:4)

问题不是“为什么*不被接受”而是“为什么+完全被接受”。

ast.literal_eval可以解析文字,但不能解析表达式。但是,在Python中,复数不表示为单个文字值;相反,它们由真实部分和虚部加在一起组成;假想部分用j发出信号。因此,literal_eval需要支持二进制+-以支持复杂的数字常量,例如1 + 2j-3.4e-5 - 1.72e9j

在许多版本中,包括Python 3.5,literal_eval需要要宽松得多 - 只要左右两边都接受任何加法和减法链-hand sides计算任何数字,因此(1 + 3) + 2 + (4 - 5)仍然被解析,即使它不是由real +组成的复数常量 想象中的部分。

无条件接受

+-:如果您尝试将2个列表一起添加,它将失败,即使它可以解析列表文字,并且为列表定义了添加:

>>> ast.literal_eval('[1] + [2]')
Traceback (most recent call last):
...
ValueError: malformed node or string: <_ast.BinOp object at 0x7fdddbe785f8>
>>> ast.literal_eval('[1, 2]')
[1, 2]
>>> [1] + [2]
[1, 2]