【问题标题】:Why does ast.literal_eval('5 * 7') fail?为什么 ast.literal_eval('5 * 7') 失败?
【发布时间】:2017-03-27 20:02:15
【问题描述】:

为什么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 没有普通的eval 强大,因此也没有那么危险。我想这使它成为两个评估中较小的一个...... :)

标签: python eval abstract-syntax-tree


【解决方案1】:

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#4907 ast.literal_eval does not properly handled complex numbers


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

【讨论】:

  • 谢谢Martjn,我怀疑是这样的。这是否意味着 AST 是评估的结果?我希望不是。
  • @LaurentLAPORTE:该函数从字符串构建 AST,然后使用 AST 构建结果。所以字符串是只解析,而不是直接执行。请参阅source code
【解决方案2】:

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

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]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    相关资源
    最近更新 更多