This is a more precise version of this question where the comments said my minimal reproducible code was too minimal, so with more information:
I want to evaluate an Expression
without having to pass the symbols along separately. My current workaround is this:
from sympy import Symbol, lambdify def evaluate_expr(expr): lambdified = lambdify(tuple(expr.free_symbols), expr) return lambdified(*[i.value for i in expr.free_symbols]) class symbol_x(Symbol): def __new__(cls, symbol, value): obj = Symbol.__new__(cls, symbol) obj.value = value return obj x = symbol_x('x', 2) y = symbol_x('y', 3) value = evaluate_expr(x / y) print(value)
This works. My problem is that expr.free_symbols
is a set
(which doesn’t maintain order), so casting it to a tuple
might create unexpected bugs. What would be the correct way of evaluating this expression?
Advertisement
Answer
You need to sort the free symbols according to some reproducible logic, like sorting by name:
def evaluate_expr(expr): fs = sorted(expr.free_symbols, key=lambda t: t.name) lambdified = lambdify(fs, expr) return lambdified(*[i.value for i in fs])
Edit for explanation:
The problem is that expr.free_symbols
returns a set. lambdify
requires a list. In Python, the conversion from a set to a list is non-deterministic. For example, say you have a set {a, b}
. When you convert it to a list you can either have [a, b]
or [b, a]
.
To fix this behavior, we can use sorted
to sort the free symbols alphabetically.