如何继承scipy Rotation类并自定义默认degrees=True的初始化方法
解决scipy Rotation子类默认degrees=True的初始化问题
错误原因
你遇到的循环调用+形状错误,根源在于:子类Rotation的__new__中调用了Rotation.from_rotvec,这里的Rotation是你定义的子类。而scipy的from_rotvec类方法在创建实例时,会调用子类的__new__,导致循环调用——第二次进入__new__时,传入的参数已经是scipy Rotation内部存储的四元数(形状(4,)),完全不符合from_rotvec要求的(3,)或(N,3)输入,因此触发报错。
正确实现
直接在子类__new__中调用父类的from_rotvec方法,避免循环,同时设置默认degrees=True:
import numpy as np from scipy.spatial.transform import Rotation as ScipyRotation import numpy.typing as npt class Rotation(ScipyRotation): def __new__(cls, rotation: npt.ArrayLike, *, degrees: bool = True): # 调用父类的from_rotvec,绕过子类的__new__循环 return ScipyRotation.from_rotvec(np.asarray(rotation), degrees=degrees) # 测试示例 if __name__ == "__main__": # 默认degrees=True rot1 = Rotation([0, 0, 0]) print("零旋转四元数:", rot1.as_quat()) # 显式指定degrees=True rot2 = Rotation([90, 0, 0], degrees=True) print("绕X轴转90度的欧拉角:", rot2.as_euler('xyz', degrees=True)) # 也可以手动指定degrees=False(弧度制) rot3 = Rotation([np.pi/2, 0, 0], degrees=False) print("绕X轴转π/2弧度的欧拉角:", rot3.as_euler('xyz', degrees=True))
补充说明
- 可以删除子类的
__init__方法:因为__new__返回的是父类ScipyRotation的实例,子类的__init__不会被执行,留着无意义。 - scipy的
Rotation是不可变类,实例创建依赖类方法而非直接构造函数,因此重写__new__是最直接的方式,但必须注意调用父类的类方法来避免循环。
内容的提问来源于stack exchange,提问作者Tom McLean
相关产品推荐
相关产品推荐

