为什么 ast.literal_eval('5 * 7') 会失败?
Why does ast.literal_eval('5 * 7') fail?
为什么 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。
ast.literal_eval()
在评估的数据中接受 +
,因为 5+2j
(复数 *)是有效的文字。 -
也是如此。为了使代码简单,没有尝试排除 +
或 -
作为二元运算符。
不允许使用其他运算符;该函数应该只接受文字,不接受表达式。
换句话说,5 + 7
工作是一个错误,但在不破坏对构造复数的支持的情况下很难修复。 implementation 将使用限制为数字操作数、一元 +
和 -
或其他二元运算符(因此您不能使用它们来连接列表或产生集合差异)。
另请参阅几个相关的 Python bugtracker 条目:#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
* 从技术上讲,2j
是一个有效的文字; Python 将 5+2j
解析为 int(5) binop(+) complex(0, 2)
,并且仅在实际执行加法时才从结果中生成一个 complex(5, 2)
对象。
问题不是 "why is *
not accepted",而是 "why is +
accepted at all"。
ast.literal_eval
可以解析文字,但不能解析表达式。但是,在 Python 中,复数不表示为单个文字值;相反,它们由加在一起的实部和虚部组成;虚部用 j
表示。 literal_eval
因此需要支持二进制 +
和 -
以支持复数常数,例如 1 + 2j
或 -3.4e-5 - 1.72e9j
.
在许多版本中,包括 Python 3.5,literal_eval
比 需要 宽松得多 - 它接受任何加法和减法链因为只要左侧和右侧都计算为 any 数字,因此 (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]
为什么 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。
ast.literal_eval()
在评估的数据中接受 +
,因为 5+2j
(复数 *)是有效的文字。 -
也是如此。为了使代码简单,没有尝试排除 +
或 -
作为二元运算符。
不允许使用其他运算符;该函数应该只接受文字,不接受表达式。
换句话说,5 + 7
工作是一个错误,但在不破坏对构造复数的支持的情况下很难修复。 implementation 将使用限制为数字操作数、一元 +
和 -
或其他二元运算符(因此您不能使用它们来连接列表或产生集合差异)。
另请参阅几个相关的 Python bugtracker 条目:#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
* 从技术上讲,2j
是一个有效的文字; Python 将 5+2j
解析为 int(5) binop(+) complex(0, 2)
,并且仅在实际执行加法时才从结果中生成一个 complex(5, 2)
对象。
问题不是 "why is *
not accepted",而是 "why is +
accepted at all"。
ast.literal_eval
可以解析文字,但不能解析表达式。但是,在 Python 中,复数不表示为单个文字值;相反,它们由加在一起的实部和虚部组成;虚部用 j
表示。 literal_eval
因此需要支持二进制 +
和 -
以支持复数常数,例如 1 + 2j
或 -3.4e-5 - 1.72e9j
.
在许多版本中,包括 Python 3.5,literal_eval
比 需要 宽松得多 - 它接受任何加法和减法链因为只要左侧和右侧都计算为 any 数字,因此 (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]