SymPy自定义cSymbol类函数内声明影响外部实例问题求解
问题:SymPy自定义cSymbol类的属性被意外修改
我为SymPy自定义了cSymbol类,用来给已声明的符号添加属性,实现代码如下:
class cSymbol(sy.Symbol): def __init__(self,name,x,**assumptions): self.x = x sy.Symbol.__init__(name,**assumptions)
但遇到一个问题:在函数内声明同名的cSymbol实例(比如名称为"a")时,会修改外部已声明的同名cSymbol实例的x属性:
def some_function(): dummy = cSymbol("a",x=2) a = cSymbol("a",x=1) print(a.x) # >> 1 some_function() print(a.x) # >> 2,预期应为1
原本以为函数内的变量都是局部的,不理解为什么会出现这种情况。除了使用不同名称,有没有办法避免这个问题?完整代码如下:
import sympy as sy class cSymbol(sy.Symbol): def __init__(self,name,x,**assumptions): self.x = x sy.Symbol.__init__(name,**assumptions) def some_function(): a = cSymbol("a",x=2) if __name__ == "__main__": a = cSymbol("a",x=1) print(a.x) # >> 1 some_function() print(a.x) # >> 2,预期应为1
问题原因
SymPy的Symbol类采用单例模式:同名且假设参数一致的符号会共享同一个实例。当你第二次创建名称为"a"的cSymbol时,SymPy不会生成新实例,而是直接返回之前已创建的那个实例。所以函数内对x属性的赋值,实际上是修改了外部那个实例的属性。
解决方法
方法1:重写__new__方法,强制生成新实例
SymPy的单例逻辑在__new__方法中实现,重写该方法可以跳过缓存,确保每次创建cSymbol都生成独立实例:
import sympy as sy class cSymbol(sy.Symbol): def __new__(cls, name, x, **assumptions): # 直接调用父类__new__,跳过SymPy的单例缓存 obj = super().__new__(cls, name, **assumptions) return obj def __init__(self, name, x, **assumptions): self.x = x super().__init__(name, **assumptions)
修改后,函数内的局部cSymbol实例和外部实例完全独立,不会互相影响。
方法2:自定义缓存键,区分带x属性的实例
如果需要保留SymPy的缓存逻辑,但希望不同x值的同名实例不共享,可以修改缓存键,把x属性加入缓存判定条件:
import sympy as sy from sympy.core.symbol import _symbol_cache class cSymbol(sy.Symbol): def __new__(cls, name, x, **assumptions): # 将x属性加入缓存键,确保只有名称、假设、x都相同时才共享实例 cache_key = (cls, name, frozenset(assumptions.items()), x) if cache_key in _symbol_cache: return _symbol_cache[cache_key] obj = super().__new__(cls, name, **assumptions) _symbol_cache[cache_key] = obj return obj def __init__(self, name, x, **assumptions): self.x = x super().__init__(name, **assumptions)
这种方式下,同名但x值不同的cSymbol会被视为不同实例,不会互相覆盖属性。
内容的提问来源于stack exchange,提问作者pfloutch
相关产品推荐
相关产品推荐

