Python 3.5 Как я могу избавиться от eval в моей функции класса

У меня есть класс с именем NumApprox, он принимает строку в качестве входных данных (математическое выражение, содержащее переменную «x»), и все методы в нем — это просто разные подходы к интеграции математического выражения с заданным числовым значением для «x».

ожидаемые примеры ввода:

  input = " x ** 2 * log( x ) "

  input = "1 / sqrt(2*pi) * exp(- x **2 / 2) "

Мне было интересно, как я могу изолировать и взять под контроль переменную «x», предоставленную строковым вводом, и использовать ее из любого места в моем классе без функции «eval».

Это то, что я сделал, но мне не нравится эта функция "eval" и, учитывая мои ограниченные знания о классах Python... Я хотел бы знать, есть ли лучшая альтернатива "eval"?

from math import pi, sqrt, exp, log

class NumApprox:

    def __init__(self, expr):
        self.expr = expr

    def pdf(self, x):
        self.x = x 
        self.ev = eval( self.expr.replace('x', 'self.x') )
        return self.ev

    def integrate_rect_method(self, A, B, n): 
        ...

person jwdasdk    schedule 06.12.2016    source источник
comment
Если вы хотите оценить произвольные выражения, не прибегая к eval, вам, вероятно, придется начать искать какой-то синтаксический анализатор.   -  person Iluvatar    schedule 06.12.2016
comment
лучше использовать такие модули, как SymPy   -  person furas    schedule 06.12.2016
comment
Кстати, как вы думаете, что будет делать self.expr.replace('x', 'self.x'), когда expr станет exp(x)?   -  person donkopotamus    schedule 06.12.2016
comment
Он вернет NameError : имя 'x' не определено, если вы не имели в виду "exp( x )", и в этом случае он вернет " exp( self.x ) ". выражение должно быть строкой; это единственный известный мне способ вызывать один и тот же объект класса для интеграции произвольных выражений.   -  person jwdasdk    schedule 06.12.2016
comment
@jwdasdk Нет, он не вернет exp(self.x) ... он вернет eself.xp(self.x).   -  person donkopotamus    schedule 07.12.2016
comment
@donkopotamus Ага! Это правда. Требуется небольшое начальное и конечное пространство вокруг «x» (т.е. self.expr.replace(' x ', 'self.x') ), и то же самое касается «x» в выражении, expr = ' exp( x ) ', чтобы оно работало.   -  person jwdasdk    schedule 07.12.2016


Ответы (1)


Возможно, используйте модуль SymPy.

from sympy import *
from sympy.parsing.sympy_parser import parse_expr

x, y, z = symbols("x y z")

input = " x ** 2 * log( x ) "

#expr = sympify(input) # `sympify` uses `eval`
expr = parse_expr(input)

print(expr)
print(expr.subs({x:2}))

input = "1 / sqrt(2*pi) * exp(- x **2 / 2) "

#expr = sympify(input) # `sympify` uses `eval`
expr = parse_expr(input)

print(expr)
print(expr.subs({x:2}))

результат:

x**2*log(x)
4*log(2)

sqrt(2)*exp(-x**2/2)/(2*sqrt(pi))
sqrt(2)*exp(-2)/(2*sqrt(pi))

Анализ

Основные операции и Sympify

person furas    schedule 06.12.2016
comment
Спасибо за предложение и демонстрацию, попробую и проверю. Однако один быстрый вопрос: сильно ли модуль SymPy полагается на evals для обработки произвольных выражений? - person jwdasdk; 06.12.2016
comment
Нашел только информацию, что sympify использует eval. Если вам нужна дополнительная информация, вам придется проверить исходный код — на странице SymPy есть ссылки на код. Если вам не нужен eval, вам придется создать синтаксический анализатор — вы можете использовать PLY — но это нужно больше работы. - person furas; 06.12.2016