Расчет значения выражения в Python для чисел, переменных и коллекций

Раздел: Основы Python -> Операторы и выражения

Вычисление значения выражения в Python

Выражение в Python может быть частью кода или строкой. В первом случае интерпретатор вычисляет его при выполнении. Во втором нужен отдельный механизм: eval, compile, ast или специализированная библиотека. Выбор зависит от источника данных, требований безопасности и типа результата.

Основной способ для контролируемой строки: функция eval с пустым словарём встроенных имён и явным словарём переменных.

expression = '2 + 3 * 4'
variables = {'x': 5, 'y': 2}
result = eval(expression, {'__builtins__': {}}, variables)
print(result)

вычислите значение выражения python (вычисление значения выражения в python)

14

команды языка python (команды python)

Пояснение шагов: строка expression содержит арифметическое выражение; второй аргумент {'__builtins__': {}} отключает доступ к стандартным функциям; третий аргумент передаёт значения переменных. Для выражения с переменной можно записать expr = 'x * y + 1', тогда результат будет равен 11.

expr = 'x * y + 1'
print(eval(expr, {'__builtins__': {}}, {'x': 5, 'y': 2}))

оператор python примеры (примеры операторов в python)

11

Проблема безопасности. eval выполняет не только арифметику, но и произвольный Python-код. Для данных из недоверенного источника этот способ не подходит. Даже ограничение __builtins__ не даёт полной изоляции, поскольку остаются атрибуты объектов и другие возможности обхода.

# Опасный пример: ввод не должен попадать в eval без проверки
user_input = '__import__("os").system("echo hello")'
# eval(user_input) выполнит команду оболочки

Решение: применять ast.literal_eval для литералов или собственный обход AST с белым списком операторов. Для формул из доверенных настроек можно использовать eval с ограниченным словарём.

Как вычислить выражение без eval для безопасности?

Модуль ast позволяет разобрать выражение в дерево и вычислить только разрешённые узлы. Этот вариант подходит для пользовательских формул с числами, переменными и базовыми операциями.

import ast
import operator

allowed_bin = {
    ast.Add: operator.add,
    ast.Sub: operator.sub,
    ast.Mult: operator.mul,
    ast.Div: operator.truediv,
    ast.Pow: operator.pow,
    ast.Mod: operator.mod,
}
allowed_unary = {ast.UAdd: operator.pos, ast.USub: operator.neg}

def safe_eval(node, variables):
    if isinstance(node, ast.Expression):
        return safe_eval(node.body, variables)
    if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
        return node.value
    if isinstance(node, ast.Name):
        return variables[node.id]
    if isinstance(node, ast.BinOp):
        op = allowed_bin[type(node.op)]
        return op(safe_eval(node.left, variables), safe_eval(node.right, variables))
    if isinstance(node, ast.UnaryOp):
        op = allowed_unary[type(node.op)]
        return op(safe_eval(node.operand, variables))
    raise ValueError('Недопустимый узел выражения')

expr = 'x * (y + 2) / 4'
tree = ast.parse(expr, mode='eval')
print(safe_eval(tree, {'x': 10, 'y': 6}))
20.0

Пояснение: ast.parse создаёт дерево без выполнения кода. Функция safe_eval спускается по узлам и вызывает только операторы из словаря. Неизвестные конструкции вызывают исключение. Такой подход удобен для калькуляторов, конфигурационных формул и правил расчета.

Как вычислить выражение, записанное прямо в коде?

Если выражение известно на этапе написания программы, отдельная функция не нужна. Интерпретатор сам выполняет операторы с учётом приоритетов.

a = 12
b = 5
result = a * b + a / b
print(result)
62.4

Приоритет операций: сначала умножение и деление, затем сложение и вычитание. Скобки меняют порядок. Этот вариант даёт максимальную скорость и проверку синтаксиса на этапе компиляции.

Как вычислить математическую формулу с функциями sin, cos, sqrt?

Для функций из math можно передать их в словарь имён для eval. Важно не открывать доступ к встроенным функциям Python.

import math

scope = {
    'sin': math.sin,
    'cos': math.cos,
    'sqrt': math.sqrt,
    'pi': math.pi,
    '__builtins__': {},
}
expr = 'sqrt(25) + cos(pi) * 2'
print(eval(expr, scope))
3.0

Пояснение: sqrt(25) даёт 5.0, cos(pi) даёт -1.0, умножение на 2 даёт -2.0, итог равен 3.0. Если формула приходит от пользователя, лучше пропускать её через безопасный AST-обход и отдельно разрешать имена функций.

Как вычислить выражение для таблицы DataFrame?

В pandas есть метод DataFrame.eval, который вычисляет выражение над колонками без создания промежуточных объектов.

import pandas as pd

df = pd.DataFrame({'price': [100, 250, 80], 'count': [2, 1, 5]})
df['total'] = df.eval('price * count')
print(df)
   price  count  total
0    100      2    200
1    250      1    250
2     80      5    400

Метод понимает имена колонок, арифметические операции и часть функций. Для сложных расчетов с внешними переменными используется параметр local_dict или @ перед именем переменной.

tax = 0.2
df['with_tax'] = df.eval('price * count * (1 + @tax)')
print(df[['total', 'with_tax']])
   total  with_tax
0    200     240.0
1    250     300.0
2    400     480.0

Как вычислить символьное выражение и подставить значения?

Библиотека SymPy работает с формулами как с символами. Это удобно для алгебраических преобразований, производных и точных дробей.

from sympy import symbols, sympify

x, y = symbols('x y')
expr = sympify('x**2 + 2*x + 1')
result = expr.subs({x: 3})
print(result)
16

Пояснение: sympify преобразует строку в символьное выражение. Метод subs заменяет символ на число. Для десятичных значений можно использовать Rational или N.

Как вычислить выражение с высокой точностью?

Для финансовых и научных расчетов с фиксированной точностью применяется decimal.Decimal. Обычные числа с плавающей точкой дают артефакты вроде 0.30000000000000004.

from decimal import Decimal, getcontext

getcontext().prec = 28
expr = 'Decimal("0.1") + Decimal("0.2")'
result = eval(expr, {'Decimal': Decimal, '__builtins__': {}})
print(result)
0.3

Пояснение: контекст задаёт 28 значащих цифр. Строки при создании Decimal сохраняют точное десятичное представление. Для формул с переменными можно подставлять Decimal-значения через словарь locals.

Типичные ошибки.

  • NameError возникает, когда переменная не передана в словарь имён или отсутствует в области видимости.
  • SyntaxError появляется при неверной строке: пропущенной скобке, лишнем операторе или тексте вместо числа.
  • ZeroDivisionError возникает при делении на ноль. Для пользовательских формул полезна проверка знаменателя.
  • Целочисленное деление // и остаток % работают по правилам Python, что может отличаться от ожиданий в других языках.
  • Переполнение стека или большое число операций в eval может привести к высокой нагрузке. Для недоверенных данных нужны ограничения длины и времени.
try:
    print(eval('10 / 0', {'__builtins__': {}}, {}))
except ZeroDivisionError as err:
    print('Ошибка:', err)
Ошибка: division by zero

Расширенные примеры вычисления выражений в Python

Ниже собраны примеры для разных типов выражений: от безопасного AST-калькулятора до векторных расчетов NumPy и точной арифметики Decimal.

Безопасный калькулятор с функциями math через ast

Пример
import ast
import math
import operator

allowed_bin = {
    ast.Add: operator.add,
    ast.Sub: operator.sub,
    ast.Mult: operator.mul,
    ast.Div: operator.truediv,
    ast.Pow: operator.pow,
    ast.Mod: operator.mod,
}
allowed_unary = {ast.UAdd: operator.pos, ast.USub: operator.neg}
allowed_funcs = {
    'sqrt': math.sqrt,
    'sin': math.sin,
    'cos': math.cos,
    'abs': abs,
}

def safe_eval(node, variables):
    if isinstance(node, ast.Expression):
        return safe_eval(node.body, variables)
    if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
        return node.value
    if isinstance(node, ast.Name):
        return variables[node.id]
    if isinstance(node, ast.BinOp):
        op = allowed_bin[type(node.op)]
        return op(safe_eval(node.left, variables), safe_eval(node.right, variables))
    if isinstance(node, ast.UnaryOp):
        op = allowed_unary[type(node.op)]
        return op(safe_eval(node.operand, variables))
    if isinstance(node, ast.Call):
        if isinstance(node.func, ast.Name) and node.func.id in allowed_funcs:
            args = [safe_eval(arg, variables) for arg in node.args]
            return allowed_funcs[node.func.id](*args)
    raise ValueError('Недопустимый узел выражения')

expr = 'sqrt(x**2 + y**2) + abs(-3)'
tree = ast.parse(expr, mode='eval')
print(safe_eval(tree, {'x': 3, 'y': 4}))
8.0

Пояснение: выражение sqrt(3**2 + 4**2) даёт 5.0, функция abs(-3) даёт 3, итог равен 8.0. Такой калькулятор не выполняет произвольные вызовы и подходит для формул из внешнего интерфейса.

Компиляция выражения для многократного расчета

Пример
code = compile('base * rate + bonus', '', 'eval')
records = [
    {'base': 100, 'rate': 0.2, 'bonus': 10},
    {'base': 200, 'rate': 0.1, 'bonus': 30},
]
for record in records:
    print(eval(code, {'__builtins__': {}}, record))
30.0
50.0

Пояснение: compile создаёт объект кода один раз. Далее eval использует его с разными словарями переменных. Это удобно для пакетной обработки строк с одинаковой структурой формулы.

Вычисление выражения в pandas с внешней переменной

Пример
import pandas as pd

df = pd.DataFrame({
    'qty': [2, 3, 5],
    'price': [10, 20, 8],
})
discount = 0.1
df['final'] = df.eval('qty * price * (1 - @discount)')
print(df)
   qty  price  final
0    2     10   18.0
1    3     20   54.0
2    5      8   36.0

Пояснение: символ @ показывает pandas, что discount является внешней переменной Python, а не колонкой DataFrame.

Векторное выражение с NumPy

Пример
import numpy as np

x = np.array([1, 2, 3])
y = np.array([10, 20, 30])
expr = 'x ** 2 + y / 2'
result = eval(expr, {'__builtins__': {}}, {'x': x, 'y': y})
print(result)
[ 6. 14. 24.]

Пояснение: x ** 2 даёт массив [1, 4, 9], y / 2 даёт [5, 10, 15]. Сложение выполняется поэлементно, результат имеет тип float.

Символьное выражение, производная и численный расчет

Пример
from sympy import symbols, diff, lambdify

x = symbols('x')
expr = x**3 - 3*x + 2
derivative = diff(expr, x)
f = lambdify(x, expr, 'math')
g = lambdify(x, derivative, 'math')
print(f(2), g(2))
4 9

Пояснение: исходная функция при x = 2 равна 4, производная 3*x**2 - 3 при x = 2 равна 9. SymPy сохраняет точную формулу, а lambdify создаёт быструю функцию для чисел.

Точная арифметика Decimal с переменными

Пример
from decimal import Decimal, getcontext, ROUND_HALF_UP

getcontext().prec = 10
price = Decimal('19.99')
qty = Decimal('3')
tax = Decimal('0.075')
expr = 'price * qty * (1 + tax)'
result = eval(expr, {'__builtins__': {}}, {'price': price, 'qty': qty, 'tax': tax})
print(result.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))
64.47

Пояснение: 19.99 * 3 * 1.075 даёт 64.46775. Метод quantize округляет до копейки с правилом ROUND_HALF_UP.

literal_eval для конфигурационных значений

Пример
from ast import literal_eval

text = "{'width': 10, 'height': 20, 'ratio': 0.5}"
config = literal_eval(text)
print(config['width'] * config['height'] * (1 + config['ratio']))
300.0

Пояснение: literal_eval безопасно разбирает строки, числа, кортежи, списки и словари. Он не вычисляет арифметические операции вроде 2 + 3, поэтому для формул нужен другой механизм.

eval с перегрузкой операторов пользовательского класса

Пример
class Money:
    def __init__(self, amount):
        self.amount = amount
    def __add__(self, other):
        return Money(self.amount + other.amount)
    def __mul__(self, k):
        return Money(self.amount * k)
    def __repr__(self):
        return f'Money({self.amount})'

a = Money(100)
b = Money(50)
result = eval('a + b * 2', {'__builtins__': {}}, {'a': a, 'b': b})
print(result)
Money(200)

Пояснение: eval использует те же правила операторов Python. Если объекты поддерживают __add__ и __mul__, выражение работает с ними как с числами.

Ограничение literal_eval на арифметике

Пример
from ast import literal_eval

try:
    print(literal_eval('2 + 3'))
except ValueError as err:
    print('ValueError:', err)
ValueError: malformed node or string

Пояснение: literal_eval принимает только литералы. Для арифметики с числами и переменными подходит безопасный AST-обход или eval с ограничениями.

Вычисление значения выражения в Python - comments

En
вычислите значение выражения python (python)