Reputation: 3648
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?
Upvotes: 0
Views: 225
Reputation: 13185
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.
Upvotes: 1