Что это такое
Паттерн Интерпретатор (Interpreter) вычисляет предложения на небольшом языке, строя дерево объектов-выражений — каждый узел знает, как интерпретировать себя. Числа интерпретируются сами в себя; узел сложения интерпретирует обе свои части и складывает их.
Он подходит для небольших языков: фильтров, формул, простых правил. Для настоящих языков нужны настоящие инструменты для парсинга.
Пример: крошечный калькулятор
Входная строка 3 + 4 - 2 превращается в дерево узлов-dataclass Number, Add и Subtract. Один вызов interpret() у корня вычисляет всё выражение.
Каждый узел интерпретирует себя сам
parse строит дерево слева направо; interpret() обходит его. Для поддержки * понадобится всего один новый тип узла — существующие останутся нетронутыми.
Вывод: полная программа на Python
from dataclasses import dataclass
# Каждый узел знает, как интерпретировать себя.
@dataclass
class Number:
value: int
def interpret(self) -> int:
return self.value
@dataclass
class Add:
left: "Expression"
right: "Expression"
def interpret(self) -> int:
return self.left.interpret() + self.right.interpret()
@dataclass
class Subtract:
left: "Expression"
right: "Expression"
def interpret(self) -> int:
return self.left.interpret() - self.right.interpret()
# Выражение — это любой из трёх типов узлов.
Expression = Number | Add | Subtract
def parse(source: str) -> Expression:
parts = source.split()
expr: Expression = Number(int(parts[0]))
for i in range(1, len(parts), 2):
number = Number(int(parts[i + 1]))
if parts[i] == "+":
expr = Add(expr, number)
else:
expr = Subtract(expr, number)
return expr
source = "3 + 4 - 2"
print(source, "=", parse(source).interpret())
Когда его использовать
Используйте его, когда пользователи или конфигурации описывают логику на небольшом языке вашей собственной разработки: поисковые фильтры, формулы цен, правила проверки.
Не используйте его, когда «язык» — это три фиксированных варианта (используйте простой if/elif), или когда это настоящий язык (используйте генератор парсеров или готовый движок).
Плюсы и минусы
Плюсы: грамматика один к одному отображается на небольшие типы; новые операции — это новые типы узлов; деревья выражений можно строить, проверять и использовать повторно.
Минусы: становится всё сложнее по мере роста грамматики; сам парсинг всё равно нужно писать; производительность скромная по сравнению с компилируемой логикой.