Python eval在函数中不起作用

use*_*327 2 python eval function

我正在使用代码来评估字符串中的数学表达式.它有效:

#!/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
Run Code Online (Sandbox Code Playgroud)

我把它包装在这样的函数中:

#!/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)
Run Code Online (Sandbox Code Playgroud)

它仍然适用于基本操作,但没有定义的功能safe_dict正常工作.5**5适用于这两个程序,但sin(pi)使用第一个代码示例,它不适用于第二个代码.追溯是

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
Run Code Online (Sandbox Code Playgroud)

Bre*_*arn 6

它失败的原因是你从数学模块导入的函数不是函数内的局部变量; 他们是全球性的.因此,当您读取locals()并插入dict时,它会为每一个插入None.你会看到这个,如果你删除了get(key, None),只是locals()[key]直接访问.

更好的方法是在数学模块上使用getattr.做import math(不from math import *)然后做safe_dict = dict((k, getattr(math, k)) for k in safe_list).