问题
I'm using this code to evaluate mathematical expressions from strings. And it works:
#!/usr/bin/env python
from __future__ import division
from math import *
expression = raw_input()
# Math functions
safe_list = ['math', 'factorial', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'hypot', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
# Create safe directory
safe_dict = dict([(key, locals().get(key, None)) for key in safe_list])
safe_dict['abs'] = abs
result = eval(expression, {"__builtins__": None}, safe_dict)
print result
I wrapped it in a function like this:
#!/usr/bin/env python
from __future__ import division
from math import *
def calculate(expression):
# Math functions
safe_list = ['math', 'factorial', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'hypot', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
# Create safe directory
safe_dict = dict([(key, locals().get(key, None)) for key in safe_list])
safe_dict['abs'] = abs
result = eval(expression, {"__builtins__": None}, safe_dict)
if isinstance(result, float) and result.is_integer():
result = int(result)
print result
expr = raw_input()
calculate(expr)
And it still works for the basic operations, but none of the functions defined in safe_dict
are working. 5**5
works with both programs, but sin(pi)
worked with the first sample of code and it's not working with the second one. The traceback is
Traceback (most recent call last):
File "stack.py", line 20, in <module>
calculate(expression)
File "stack.py", line 14, in calculate
result = eval(expression, {"__builtins__": None}, safe_dict)
File "<string>", line 1, in <module>
TypeError: 'NoneType' object is not callable
回答1:
The reason it fails is that the functions you import from the math module are not local variables inside the function; they are global. So when you read locals() and insert into the dict, it inserts None for every single one. You would see this if you removed the get(key, None)
and just accessed locals()[key]
directly.
A better way is to use getattr on the math module. Do import math
(not from math import *
) and then do safe_dict = dict((k, getattr(math, k)) for k in safe_list)
.
回答2:
Within your calculate()
function, locals()
does not include the functions imported from math
. Therefore, safe_dict
is populated with a lot of None
.
You could build up the safe_dict
outside of calculate()
, which would also have the advantage of performing better if you're making multiple calls to calculate()
.
回答3:
This might be because you have 'math'
in safe_list
, and math
is a module. To me, it seems like eval
is doing math()
, which will cause it to choke the way it is doing.
Try removing 'math'
from safe_list
and see if that helps at all.
On a side note: I'm not sure this is really the best way to do what you want to do. I think a design change is called for.
来源:https://stackoverflow.com/questions/11419463/python-eval-not-working-within-a-function