这在Python2上不起作用的原因在于它实现了literal_eval
.当右操作数是复数时,原始实现仅对加法和减法执行数字求值.这在句法上对于复数表示为文字是必要的.
这是Python 3中的was changed,因此它支持任何类型的有效数字表达式位于加法和减法的任一侧.然而,literal_eval
的使用仍然局限于加法和减法.
这主要是因为literal_eval
应该是一个将单个constant文本(表示为字符串)转换为Python对象的函数.有点像简单内置类型的向后repr
.不包括实际的表达式求值,而这一点在Python3中也适用,这只是它的实现带来的一个很好的副作用.
为了计算实际表达式,而不必使用eval
(我们不想使用eval
),我们可以编写自己的表达式计算算法,该算法在AST上运行.这非常简单,尤其是对于简单的数字算术运算(例如构建自己的计算器等).我们只需将字符串解析为AST,然后通过查看不同的 node 类型并应用正确的操作来判断生成的树.
比如:
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)
正如您所看到的,这个实现非常简单.当然,它还不支持更复杂的东西,比如指数运算和一些一元 node ,但添加它们并不太困难.而且效果很好:
>>> arithmeticEval('4+2')
6
>>> arithmeticEval('4*1+2*6/3')
8
以后甚至可以引入更复杂的东西(例如,sin()
之类的函数调用).