Оценка математических выражений в Python

Я хочу, чтобы токенизировать заданное математическое выражение в дереве синтаксиса следующим образом:

((3 + 4 - 1) * 5 + 6 * -7) / 2

                          '/'
                        /     \
                       +        2
                    /     \
                  *         *
                /   \     /   \
               -     5   6     -7
             /   \
            +     1
          /   \
         3     4

Есть ли какой-нибудь чистый способ Python для этого? Как передача строки в Python, а затем возврат в виде дерева, как указано выше.

Спасибо.

Ответ 1

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

В частности, метод ast.parse() будет полезен для вашего приложения:

>>> import ast
>>> ast.parse("(1+2)*3", "", "eval")
<_ast.Expression object at 0x88950>
>>> ast.dump(_)
'Expression(body=BinOp(left=BinOp(left=Num(n=1), op=Add(), right=Num(n=2)), op=Mult(), right=Num(n=3)))'

Ответ 3

Существует много хороших, установленных алгоритмов для синтаксического анализа математических выражений, подобных этому. Одним из особенно хороших является Dijkstra алгоритм шунтирования, который можно использовать для создания такого дерева. Я не знаю конкретной реализации на Python, но алгоритм не является особенно сложным, и не стоит слишком долго бить его.

Кстати, более точный термин для дерева, которое вы строите, это дерево или абстрактное синтаксическое дерево.

Ответ 4

Я не знаю способ "чистого питона", который уже реализован для вас. Однако вы должны проверить ANTLR (http://www.antlr.org/) это парсер с открытым исходным кодом lexer, и он имеет API для нескольких языков, включая python. Также на этом веб-сайте есть отличные видеоуроки, которые покажут вам, как делать именно то, что вы просите. Это очень полезный инструмент, чтобы знать, как использовать в целом.

Ответ 5

Вы можете сделать это с помощью модуля Python ast.

https://docs.python.org/3.6/library/ast.html

theoperation - наша математическая операция, которую мы хотим оценить, мы используем isinstance для того, чтобы знать тип, который он есть, если его число, если это бинарный оператор (+, *,..). Вы можете читать https://greentreesnakes.readthedocs.io/en/latest/tofrom.html, как работает ast

И для того, чтобы этот метод работал, мы можем использовать: оценить (ast.parse(theoperation, mode = 'eval'). body)

def evaluate(theoperation): 
    if (isinstance(theoperation, ast.Num)):
        return theoperation.n
    if (isinstance(theoperation, ast.BinOp)):
        leftope= evaluate(theoperation.left)
        rightope=evaluate(theoperation.right)   
        if (isinstance(theoperation.op, ast.Add)):
            return left+right
        elif (isinstance(theoperation.op, ast.Sub)):
            return left-right
        elif (isinstance(theoperation.op, ast.Mult)):
            return left*right
        elif (isinstance(theoperation.op, ast.Div)):
            return left/right
        elif (isinstance(theoperation.op, ast.Pow)):
            return left**right