2012-04-09 4 views
4

Я пишу программу, в которой пользователи должны иметь возможность использовать самоналоженные математические функции, содержащие функции от numpy и scipy, например. scipy.special.wofz().Python: Использование sympy.sympify для выполнения безопасного eval() для математических функций

Эти функции будут храниться в файлах и импортироваться в виде строк программой. Я огляделся и увидел, что eval() или exec() - это не безопасный способ сделать это. например. here.

Проблема с безопасностью будет заключаться в том, что хорошие пользователи загружают файл от злых пользователей, которые получают доступ к хорошей системе пользователей.

Я думал о делать что-то вроде этого:

#!/bin/python 
from scipy.special import * 
from numpy import * 
import sympy 

# Define variable a 
vars = {"a":1} 
# This is the string I get from a file 
string = "wofz(a)" 

parsed_string = sympy.sympify(string) 
parsed_string.evalf(subs=vars) 

Однако, это не работает. Он возвращается только:

wofz(a) 

wofz (a) не оценивается. Это даже должно работать так?

У меня была другая идея: Итак, я подумал, что после того, как эта математическая функция прошла через sympify, она должна быть безопасной. Я мог бы просто сделать что-то вроде этого:

globals = {wofz:wofz} 
eval(str(parsed_string), vars, globals) 

, который отлично работает и возвращает:

(0.36787944117144233+0.60715770584139372j) 

является то, что безопасно? Я знаю, что это не приятно.

Пожалуйста, помогите.

ответ

4

Используйте sympy, это вариант более безопасный.

import sympy 
from sympy.core.function import Function 
from sympy.core import S 
from sympy import sympify 
from sympy.functions import im 
from scipy.special import wofz 

class Wofz(Function): 
    is_real = True 
    @classmethod 
    def _should_evalf(csl,arg): 
     return True 
    def as_base_exp(cls): 
     return cls,S.One 

    def _eval_evalf(cls, prec): 
     return sympy.numbers.Number(im(wofz(float(cls.args[0])))) 

print sympify("Wofz(2)",{'Wofz':Wofz}).evalf() 

Output (вы должны обрабатывать мнимую часть как-то):

0.340026217066065 
+0

ahh, поэтому проблема заключается в том, что в 'sympy.functions' нет определения функции' wofz'. – user1322192

+0

Вы хотели использовать 're' вместо' im' хотя, верно? Что делает флаг 'is_real'? Можно сделать что-то вроде 'return Number (re (...)) + Number (im (...)) * 1j', чтобы получить мнимые числа там. – user1322192

+1

@ user1322192 Вы всегда можете внести свой вклад в SymPy, в любом случае это open-source. См. [Рабочий процесс разработки] (https://github.com/sympy/sympy/wiki/Development-workflow), он написан достаточно четко. – VPeric

0

Если строка является единственной ненадежной информацией, я думаю, что должно быть безопасным следующее:

Для используйте eval() с ограниченным словарем, передайте ему второй аргумент, который является словарем разрешенных имен, где __builtins__ определяется чем-то безвредным (см. http://docs.python.org/library/functions.html#eval).

>>> import numpy as np 
>>> d = dict(linspace=np.linspace, range=range, __builtins__=None) 
>>> eval("str(1), 2+2") 
('1', 4) 
>>> eval("str(1)", d) 
Traceback (most recent call last) 
NameError: name 'str' is not defined 

>>> eval("{'a': linspace(0, 0.5, 6)}, range(2)", d) 
({'a': array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5])}, [0, 1]) 
>>> eval("linspace.__dict__", d) 
Traceback (most recent call last) 
RuntimeError: function attributes not accessible in restricted mode 

 Смежные вопросы

  • Нет связанных вопросов^_^