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

Lau*_*RTE 8 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 ...>
Run Code Online (Sandbox Code Playgroud)

文件没有解释这一点.

在SO上回答这个问题之后我发现了这个问题:得到一个字符串的结果.

Mar*_*ers 14

ast.literal_eval()接受+评估数据,因为5+2j(复数*)是有效的文字.这同样适用于-.为了使代码简单,不要尝试排除+-作为二元运算符.

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

换句话说,这5 + 7是一个错误,但在不破坏对构造复数的支持的情况下难以修复.该实施限制使用到的数字,一元操作数+-,或其他二进制运算符(所以你不能用这些来连接列表或产生一组差异).

另请参阅几个相关的Python bugtracker条目:#25335 ast.literal_eval无法解析带有前导"+"的数字,#22525 ast.literal_eval()不执行文档说的操作,#4907 ast.literal_eval无法正确处理复数


*从技术上讲,这2j是一个有效的文字; Python 在实际执行添加时解析5+2jint(5) binop(+) complex(0, 2),并且稍后才complex(5, 2)从结果中生成对象.


Ant*_*ala 7

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

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

在许多版本中,包括 Python 3.5,literal_eval比它需要的要宽松得多- 只要左侧和右侧的计算结果为任何数字,它就接受任何加法和减法链,因此(1 + 3) + 2 + (4 - 5)仍然被解析,即使它不是由实部+虚部组成的复常数。


+并且-不会被无条件接受:如果您尝试将 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]
Run Code Online (Sandbox Code Playgroud)