众所周知,使用eval()是一种潜在的安全风险,因此推广使用ast.literal_eval(node_or_string)
然而,在Python2.7中,当运行此示例时,它会返回ValueError: malformed string:
>>> ast.literal_eval("4 + 9")而在python 3.3中,此示例的工作方式与预期不谋而合:
>>> ast.literal_eval('4+9')
13为什么它运行在python 3上,而不是python 2上?如何在不使用危险的eval()函数的情况下在Python2.7中修复它?
发布于 2013-12-24 01:47:59
它是为了支持复数(从issue 4907开始)。例如,解析器将1 + 2j解析为由整数、加法运算和imaginary literal组成的表达式;但由于complex numbers是内置类型,因此ast.literal_eval最好支持复数语法。
2.x和3.x之间的change in behaviour是为了支持以“错误的方式”写入复数,例如1j + 2;它允许任意加法或减法表达式的事实是一个(大多是意想不到的)副作用。
如果要解析任意算术表达式,则应该解析为语法树(使用ast.parse)、verify it with a whitelist,然后进行求值。
发布于 2013-12-24 01:35:43
使用源码,卢克!
http://hg.python.org/cpython/file/2.7/Lib/ast.py#l40 http://hg.python.org/cpython/file/3.2/Lib/ast.py#l39
你会在那里找到你的答案。具体地说,2.7版本对line 70有一个奇怪的限制,即BinOp的右侧节点是复杂的。
>>> sys.version
'2.7.3 (default, Sep 26 2013, 20:03:06) \n[GCC 4.6.3]'
>>> ast.literal_eval('9 + 0j')
(9 + 0j)
>>> ast.literal_eval('0j + 9')
ValueError: malformed string我猜2.7的目的是允许对复杂的文字进行literal_eval,例如像9 + 0j这样的数字,它从来没有打算做简单的整数加法。然后在Python3中,他们增强了literal_eval来处理这些情况。
发布于 2013-12-24 10:46:14
使用pyparsing拼凑一个简单的表达式求值器并不太难。
假设您要计算以下表达式类型的表达式,包括括号:
2+3
4.0^2+5*(2+3+4)
1.23+4.56-7.890
(1+2+3+4)/5
1e6^2/1e7这是对SimpleCalc示例的简化:
import pyparsing as pp
import re
ex='''\
2+3
4.0^2+5*(2+3+4)
1.23+4.56-7.890
(1+2+3+4)/5
1e6^2/1e7'''
e = pp.CaselessLiteral('E')
dec, plus, minus, mult, div, expop=map(pp.Literal,'.+-*/^')
addop = plus | minus
multop = mult | div
lpar, rpar=map(pp.Suppress,'()')
p_m = plus | minus
num = pp.Word(pp.nums)
integer = pp.Combine( pp.Optional(p_m) + num )
floatnumber = pp.Combine( integer +
pp.Optional( dec + pp.Optional(num) ) +
pp.Optional( e + integer ) )
stack=[]
def pushFirst(s, l, t):
stack.append( t[0] )
expr=pp.Forward()
atom = ((floatnumber | integer).setParseAction(pushFirst) |
( lpar + expr.suppress() + rpar )
)
factor = pp.Forward()
factor << atom + pp.ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
term = factor + pp.ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
expr << term + pp.ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
pattern=expr+pp.StringEnd()
opn = { "+" : ( lambda a,b: a + b ),
"-" : ( lambda a,b: a - b ),
"*" : ( lambda a,b: a * b ),
"/" : ( lambda a,b: a / b ),
"^" : ( lambda a,b: a ** b ) }
def evaluateStack(stk):
op = stk.pop()
if op in "+-*/^":
op2 = evaluateStack(stk)
op1 = evaluateStack(stk)
return opn[op](op1, op2)
elif re.search('^[-+]?[0-9]+$',op):
return int(op)
else:
return float(op)
for line in ex.splitlines():
parse=pattern.parseString(line)
s=stack[:]
print('"{}"->{} = {}'.format(line,s,evaluateStack(stack))) 打印:
"2+3"->['2', '3', '+'] = 5
"4.0^2+5*(2+3+4)"->['4.0', '2', '^', '5', '2', '3', '+', '4', '+', '*', '+'] = 61.0
"1.23+4.56-7.890"->['1.23', '4.56', '+', '7.890', '-'] = -2.1000000000000005
"(1+2+3+4)/5"->['1', '2', '+', '3', '+', '4', '+', '5', '/'] = 2.0
"1e6^2/1e7"->['1E6', '2', '^', '1E7', '/'] = 100000.0https://stackoverflow.com/questions/20748202
复制相似问题