Python子类J_Eig调用父类方法后变为Single_Ket实例,如何避免重写代码?
问题根源
报错的核心原因是父类Single_Ket的算术运算方法硬编码返回了Single_Ket类实例,子类J_Eig的实例经过乘法运算后类型会被向上转为父类,丢失子类的__rmatmul__方法,导致第二次调用@运算符时报错。
解决方案
不需要重写子类的所有算术方法,只要调整父类的实现逻辑即可实现零代码重复:
最优方案:父类增加实例创建辅助方法(解耦性最好)
给父类新增通用的同类型实例创建方法,子类只需重写该方法适配自己的初始化参数即可,不需要修改任何算术运算逻辑:
from sympy import Rational, sqrt, I import sympy as sp class Single_Ket: def __init__(self, label: tuple, ket_coefficient = 1): self.label = label self.coeff = ket_coefficient # 新增辅助方法:用于生成同类型的新实例,子类可重写 def _new_instance(self, new_coeff): return Single_Ket(self.label, new_coeff) # 所有算术方法统一调用_new_instance,不再硬写返回类名 def __mul__(self, Scalar_Const): return self._new_instance(self.coeff * Scalar_Const) def __rmul__(self, Scalar_Const): return self._new_instance(self.coeff * Scalar_Const) def __truediv__(self, Scalar_Const): if type(Scalar_Const) == int: new_coeff = Rational(self.coeff, Scalar_Const) else: new_coeff = self.coeff/Scalar_Const return self._new_instance(new_coeff) def __neg__(self): return self._new_instance(-self.coeff) class J_Eig(Single_Ket): def __init__(self, j, m, Coeff = 1): super().__init__((j, m), Coeff) self.j = j self.m = m self.State_Coeff = Coeff # 重写父类辅助方法,返回J_Eig类型实例 def _new_instance(self, new_coeff): return J_Eig(self.j, self.m, new_coeff) def __rmatmul__(self, X): # 优化判断逻辑:避免依赖dir返回值的顺序,稳定性更高 if str(X) in {'J_Plus', 'J_Minus', 'J_Z'}: return eval(f'J_Op.{X}(self)') class J_Op: @staticmethod def J_Plus(J_State): return sqrt(J_State.j*(J_State.j + 1) - J_State.m*(J_State.m + 1)) * J_Eig(J_State.j, J_State.m + 1, J_State.State_Coeff) # 测试代码 psi = J_Eig(1, 0, 1) psi_2 = 'J_Plus' @ psi print('J_Plus' @ psi) print('J_Plus' @ psi_2)
修改完成后,所有算术运算返回的实例类型和调用者完全一致,J_Eig实例乘完还是J_Eig类型,第二次调用@运算符不会再报错。
内容的提问来源于stack exchange,提问作者QF2QP
相关产品推荐
相关产品推荐

