<p>这在Python 2上不起作用的原因在于它实现了<code>literal_eval</code>。原始实现仅在右操作数为复数时对加法和减法执行数值计算。这在语法上是必要的,复数要表示为一个文字。</p>
<p>这是Python 3中的<a href="https://hg.python.org/cpython/rev/884c71cd8dc6/" rel="noreferrer">was changed</a>,因此它支持任何类型的有效数字表达式位于加减运算的任何一边。然而,<code>literal_eval</code>的使用仍然限于加法和减法。</p>
<p>这主要是因为<code>literal_eval</code>应该是一个函数,它将单个<em>常量</em>文本(表示为字符串)转换为Python对象。有点像简单内置类型的向后<code>repr</code>。实际的表达式求值不包括在内,而这与Python3一起工作的事实只是它实现的一个很好的副作用。</p>
<p>为了计算实际表达式,不必使用<code>eval</code>(我们不想这样做),我们可以编写自己的表达式计算算法,该算法在AST上运行。这是非常简单的,特别是对数字进行简单的算术运算(例如构建自己的计算器等)。我们只需将字符串解析为AST,然后通过查看不同的节点类型并应用正确的操作来计算结果树。</p>
<p>像这样的:</p>
<pre><code>import ast, operator
binOps = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.div,
ast.Mod: operator.mod
}
def arithmeticEval (s):
node = ast.parse(s, mode='eval')
def _eval(node):
if isinstance(node, ast.Expression):
return _eval(node.body)
elif isinstance(node, ast.Str):
return node.s
elif isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.BinOp):
return binOps[type(node.op)](_eval(node.left), _eval(node.right))
else:
raise Exception('Unsupported type {}'.format(node))
return _eval(node.body)
</code></pre>
<p>如您所见,这个实现非常简单。当然,它还不支持更复杂的东西,比如指数运算和一些一元节点,但是添加它并不太困难。而且效果很好:</p>
<pre><code>>>> arithmeticEval('4+2')
6
>>> arithmeticEval('4*1+2*6/3')
8
</code></pre>
<p>以后甚至可以引入更复杂的内容(例如,函数调用<code>sin()</code>)。</p>