使用pickle存储SymPy对象报错:'One'对象不可订阅
SymPy线性方程组缓存报错:'One' object is not subscriptable 解决方法
问题场景
用SymPy求解线性方程组时计算耗时较长,为重复使用结果,通过pickle将计算结果缓存到磁盘,但修改后的代码运行时报错:
TypeError: 'One' object is not subscriptable
报错代码
@property def solutions(self) -> list[Expr]: directory = SYMPY_DATA_PATH filename = os.path.join(directory, f'{self.__class__.__name__}.pkl') if not os.path.exists(directory): os.makedirs(directory) if os.path.exists(filename): with open(filename, 'rb') as f: print(f"Loading {filename}") solution_set = pickle.load(f) else: solution_set = together(linsolve(self.equations, self.pins)) print(f"Saving {filename}") with open(filename, 'wb') as f: pickle.dump(list(solution_set)[0], f) return list(solution_set)[0] def solution(self, pin) -> Expr: return self.solutions[pin]
原正常运行代码
@property def solutions(self) -> list[Expr]: solution_set = together(linsolve(self.equations, self.pins)) return list(solution_set)[0]
错误原因
缓存逻辑存在不一致:
- 首次计算时,
solution_set是SymPy的解集对象(如FiniteSet),我们将list(solution_set)[0](即最终需要的解列表)存入pickle。 - 加载缓存时,直接将解列表赋值给了
solution_set,随后又执行list(solution_set)[0]——这相当于把解列表的第一个元素(单个SymPy表达式)作为返回值。 - 调用
solution方法时,self.solutions实际是单个表达式对象(而非列表),对其做下标操作自然触发"不可下标"的错误。
修复代码
调整缓存逻辑,直接缓存并返回解列表,避免重复转换:
@property def solutions(self) -> list[Expr]: directory = SYMPY_DATA_PATH filename = os.path.join(directory, f'{self.__class__.__name__}.pkl') if not os.path.exists(directory): os.makedirs(directory) if os.path.exists(filename): with open(filename, 'rb') as f: print(f"Loading {filename}") # 直接加载缓存的解列表 solution_list = pickle.load(f) else: solution_set = together(linsolve(self.equations, self.pins)) solution_list = list(solution_set)[0] print(f"Saving {filename}") with open(filename, 'wb') as f: pickle.dump(solution_list, f) # 直接返回解列表 return solution_list def solution(self, pin) -> Expr: return self.solutions[pin]
修复说明
- 首次计算时,直接提取解列表并缓存,后续加载时直接复用该列表。
- 无论计算还是加载,
solutions属性始终返回解列表,调用solution方法时的下标操作会正常作用于列表,避免报错。
内容的提问来源于stack exchange,提问作者photonic_aardvark
相关产品推荐
相关产品推荐

