如何强制SymPy自定义函数每次调用时重新求值
解决SymPy函数缓存导致无法获取numpy数组最新值的问题
SymPy的Function类默认会缓存参数对应的实例,一旦某个参数组合的函数实例被创建(比如U(2,1)),后续调用相同参数时会直接返回缓存结果,不会重新执行eval方法,这就导致修改numpy数组u后,相同参数的U函数无法获取最新值。
解决方案1:禁用函数实例缓存
在自定义的U类中添加_cache = False属性,强制SymPy每次调用函数时都重新创建实例并执行eval方法:
import numpy as np import sympy as smp # 初始化u数组(假设steps和cons已定义) u = np.zeros((steps+1, cons['m']+1), dtype='float') u[:, :] = np.nan u[:, 0] = 0 u[0, 1:-1] = 1 u[:, -1] = 0 class U(smp.Function): _cache = False # 禁用实例缓存 @classmethod def eval(cls, i, j): global u if isinstance(i, smp.Integer) and isinstance(j, smp.Integer): val = u[i, j] if not np.isnan(val): return val
修改后每次调用U(i,j)都会重新检查u数组的最新值,比如:
print(U(2, 1)) # 输出U(2,1) u[2, 1] = 2 print(U(2, 1)) # 输出2.0
解决方案2:修改数组后手动清除缓存
如果不想完全禁用缓存,可以在修改u数组后,手动清除U类的缓存字典,这样下次调用相同参数时会重新执行eval:
# 修改u数组 u[2, 1] = 2 # 清除U函数的缓存 U._cache.clear() # 此时调用会重新求值 print(U(2, 1)) # 输出2.0
注意事项
- 使用
global u的方式适合简单场景,复杂场景建议将u封装为类属性或通过闭包传递,避免全局变量带来的副作用。 - 禁用缓存会略微降低性能(每次调用都要创建新实例),但对于需要实时获取数组最新值的场景,这是必要的权衡。
内容的提问来源于stack exchange,提问作者Sunil Kumar
相关产品推荐
相关产品推荐

