Python eval not working within a function

有些话、适合烂在心里 提交于 2019-12-07 19:09:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!