如何在Python/Cython中让isinstance判定自定义类为float类型?
解决方案
方法1:通过抽象基类注册(Python/Cython通用)
Python的numbers模块提供了数值类型的抽象基类,float属于numbers.Real的子类。将自定义类注册为numbers.Real的虚拟子类后,pytest.approx会识别并处理近似比较(其底层逻辑兼容Real类型):
from numbers import Real class Angle: def __init__(self, value): self.value = max(0.0, min(360.0, float(value))) def __float__(self): return self.value # 注册为Real的虚拟子类 Real.register(Angle)
此时isinstance(Angle(90), Real)返回True,pytest.approx能正常执行近似校验。
方法2:自定义元类修改isinstance行为(仅Python)
若必须让isinstance(obj, float)返回True,可通过自定义元类重写__instancecheck__方法,但这种方式属于“类型欺骗”,可能引发兼容性问题,需谨慎使用:
class FloatMeta(type): def __instancecheck__(cls, instance): return isinstance(instance, float) or isinstance(instance, Angle) class Angle(metaclass=FloatMeta): def __init__(self, value): self.value = max(0.0, min(360.0, float(value))) def __float__(self): return self.value
执行isinstance(Angle(90), float)会返回True,但依赖float严格类型检查的代码可能出现异常。
方法3:适配pytest.approx的自定义比较(更安全)
无需修改isinstance行为,直接让自定义类支持pytest.approx的比较逻辑,这种方式不会破坏原生类型检查规则:
from pytest import approx class Angle: def __init__(self, value): self.value = max(0.0, min(360.0, float(value))) def __float__(self): return self.value def __eq__(self, other): if isinstance(other, approx.__class__): return float(self) == other return float(self) == other # 或实现pytest规范的__approx__方法 def __approx__(self, other, rel=None, abs=None): if rel is not None: return abs(float(self) - float(other)) <= max(rel * abs(float(other)), abs) return abs(float(self) - float(other)) <= abs
Cython扩展类型的特殊处理
在Cython中,可直接沿用抽象基类注册的逻辑,或自定义类型的检查行为:
from cpython cimport PyObject from numbers cimport Real cdef class Angle: cdef double value def __init__(self, double value): if value <= 0: self.value = 0.0 elif value >= 360: self.value = 360.0 else: self.value = value def __float__(self): return self.value # 注册为Real的虚拟子类 Real.register(Angle)
内容的提问来源于stack exchange,提问作者JuanT
相关产品推荐
相关产品推荐

