Why does the literal evaluation of 5 * 7
fail, while 5 + 7
doesn't?
为什么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 ...>
The documentation doesn't explain this.
文档没有解释这一点。
I found that problem after answering this question on SO: Getting the result of a string.
在SO上回答这个问题之后我发现了这个问题:得到一个字符串的结果。
2 个解决方案
#1
10
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.
ast.literal_eval()在计算数据中接受+,因为5 + 2j(复数*)是有效的文字。这同样适用于 - 。为了使代码简单,不要尝试将+或 - 排除为二元运算符。
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).
换句话说,5 + 7工作是一个错误,但是如果不破坏对构造复数的支持就很难修复。该实现限制了对数字,一元+和 - 或其他二元运算符的操作数的使用(因此您不能使用它们来连接列表或产生集合差异)。
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
另请参阅几个相关的Python bugtracker条目:#25335 ast.literal_eval无法解析带有前导“+”的数字,#22525 ast.literal_eval()不执行文档说的操作,#4907 ast.literal_eval无法正确处理复数
* 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.
*从技术上讲,2j是一个有效的文字; Python将5 + 2j解析为int(5)binop(+)complex(0,2),并且稍后仅在实际执行添加时从结果中生成复杂(5,2)对象。
#2
4
The question is not "why is *
not accepted" but rather "why is +
accepted at all".
问题不是“为什么不被接受”而是“为什么+被接受”。
ast.literal_eval
can parse literals, but not expressions. However, in Python, complex numbers are not expressed as a single literal value; instead they consist of the real part and imaginary part added together; the imaginary part is signalled with j
. literal_eval
thus needs to support binary +
and -
to support complex number constants such as 1 + 2j
or -3.4e-5 - 1.72e9j
.
ast.literal_eval可以解析文字,但不能解析表达式。但是,在Python中,复数不表示为单个文字值;相反,它们由真实部分和虚部加在一起组成;假想部分用j表示。因此,literal_eval需要支持二进制+和 - 以支持复数常量,例如1 + 2j或-3.4e-5 - 1.72e9j。
In many versions, including Python 3.5, literal_eval
is much more lax than it needs to be - it accepts any chain of additions and subtractions for as long as both the left and right-hand sides evaluate to any number, thus (1 + 3) + 2 + (4 - 5)
is still parsed, even if it is not complex constant consisting of real + imaginary part.
在许多版本中,包括Python 3.5,literal_eval比它需要的要宽松得多 - 只要左侧和右侧都评估为任何数字,它就接受任何加法和减法链,因此(1 + 3) + 2 +(4 - 5)仍然被解析,即使它不是由实部+虚部组成的复数常数。
+
and -
are not accepted unconditionally: if you try to add 2 lists together, it will fail, even though it can parse list literals, and addition is defined for lists:
+和 - 不被无条件接受:如果你试图一起添加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]
#1
10
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.
ast.literal_eval()在计算数据中接受+,因为5 + 2j(复数*)是有效的文字。这同样适用于 - 。为了使代码简单,不要尝试将+或 - 排除为二元运算符。
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).
换句话说,5 + 7工作是一个错误,但是如果不破坏对构造复数的支持就很难修复。该实现限制了对数字,一元+和 - 或其他二元运算符的操作数的使用(因此您不能使用它们来连接列表或产生集合差异)。
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
另请参阅几个相关的Python bugtracker条目:#25335 ast.literal_eval无法解析带有前导“+”的数字,#22525 ast.literal_eval()不执行文档说的操作,#4907 ast.literal_eval无法正确处理复数
* 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.
*从技术上讲,2j是一个有效的文字; Python将5 + 2j解析为int(5)binop(+)complex(0,2),并且稍后仅在实际执行添加时从结果中生成复杂(5,2)对象。
#2
4
The question is not "why is *
not accepted" but rather "why is +
accepted at all".
问题不是“为什么不被接受”而是“为什么+被接受”。
ast.literal_eval
can parse literals, but not expressions. However, in Python, complex numbers are not expressed as a single literal value; instead they consist of the real part and imaginary part added together; the imaginary part is signalled with j
. literal_eval
thus needs to support binary +
and -
to support complex number constants such as 1 + 2j
or -3.4e-5 - 1.72e9j
.
ast.literal_eval可以解析文字,但不能解析表达式。但是,在Python中,复数不表示为单个文字值;相反,它们由真实部分和虚部加在一起组成;假想部分用j表示。因此,literal_eval需要支持二进制+和 - 以支持复数常量,例如1 + 2j或-3.4e-5 - 1.72e9j。
In many versions, including Python 3.5, literal_eval
is much more lax than it needs to be - it accepts any chain of additions and subtractions for as long as both the left and right-hand sides evaluate to any number, thus (1 + 3) + 2 + (4 - 5)
is still parsed, even if it is not complex constant consisting of real + imaginary part.
在许多版本中,包括Python 3.5,literal_eval比它需要的要宽松得多 - 只要左侧和右侧都评估为任何数字,它就接受任何加法和减法链,因此(1 + 3) + 2 +(4 - 5)仍然被解析,即使它不是由实部+虚部组成的复数常数。
+
and -
are not accepted unconditionally: if you try to add 2 lists together, it will fail, even though it can parse list literals, and addition is defined for lists:
+和 - 不被无条件接受:如果你试图一起添加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]