SymPy符号与表达式存储方案咨询:实现计算可复现性
SymPy符号与表达式关联存储的实现方案
需求背景
希望通过SymPy输出可复现的计算过程,以面积和体积计算为例,期望生成的代码输出为:
import sympy as sp from sympy.abc import * display(sp.Eq(A, a*b), sp.Eq(V, A*h), sp.Eq(V, a*b*h))
此前尝试的三种方案均存在痛点:
- 存储为
sp.Eq对象:需反复手动替换符号与对应方程,操作繁琐且易出错; - 直接覆盖符号:计算过程自然,但无法生成
sp.Eq(V, A*h)这类中间步骤的等式输出,复杂计算时逻辑链不清晰; - 字典存储表达式:依赖关系增多后,手动替换表达式的操作完全不可行。
期望有类似sp.symbols()的工具,能同时绑定符号与对应表达式,支持SymPy运算,且能分别以符号或表达式形式展示输出。
解决方案建议
方案1:自定义SymExpr类绑定符号与表达式
通过自定义类封装符号和表达式,重载必要的魔法方法以支持SymPy运算,同时保留生成等式的能力:
import sympy as sp from sympy.abc import * class SymExpr: def __init__(self, symbol, expr=None): self.symbol = symbol self.expr = expr if expr is not None else symbol # 打印时显示符号名 def __repr__(self): return repr(self.symbol) # 支持生成等式 def to_eq(self): return sp.Eq(self.symbol, self.expr) # 重载乘法运算,返回新的SymExpr对象 def __mul__(self, other): if isinstance(other, SymExpr): return SymExpr(sp.Dummy(), self.expr * other.expr) return SymExpr(sp.Dummy(), self.expr * other) # 按需重载其他运算,如加法、减法等 def __add__(self, other): if isinstance(other, SymExpr): return SymExpr(sp.Dummy(), self.expr + other.expr) return SymExpr(sp.Dummy(), self.expr + other) # 使用示例 A = SymExpr(A, a*b) V_expr = A * h V = SymExpr(V, V_expr.expr) # 输出期望的等式 display(A.to_eq(), sp.Eq(V.symbol, A.symbol * h), V.to_eq())
方案2:继承sp.Symbol实现带追踪的符号
通过继承SymPy原生的Symbol类,给符号附加expr属性来存储对应表达式,同时保留符号的原生运算能力:
import sympy as sp class TrackedSymbol(sp.Symbol): def __new__(cls, name, expr=None, **kwargs): obj = super().__new__(cls, name, **kwargs) obj.expr = expr if expr is not None else obj return obj # 用于更新表达式 def set_expr(self, expr): self.expr = expr return self # 使用示例 a, b, h = sp.symbols('a b h') A = TrackedSymbol('A').set_expr(a*b) V = TrackedSymbol('V').set_expr(A * h) # 输出中间步骤与最终结果 display(sp.Eq(A, A.expr), sp.Eq(V, A * h), sp.Eq(V, V.expr))
总结
自定义类的方式可以同时管理符号和对应的表达式,既支持正常的SymPy运算,又能随时生成sp.Eq形式的步骤输出,满足计算可复现的需求。可根据实际使用场景,补充重载更多魔法方法(如除法、幂运算等)来覆盖常用操作。
内容的提问来源于stack exchange,提问作者PascalGitz
相关产品推荐
相关产品推荐

