You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python单元测试中如何不替换isinstance()即可mock type()的返回值

解决方案

方案1:保留原有type()检查逻辑,仅调整单元测试代码

如果你不想修改业务侧的字典查找逻辑,只需要在创建Mock对象后手动修改其__class__属性,即可让type()调用返回你期望的类:

mock_obj = Mock(spec=Foo)
mock_obj.__class__ = Foo # 强制type()返回Foo类
generic_type_func(mock_obj) # 不会再触发KeyError
  • 优点:完全无需修改业务代码,改动成本极低。

方案2:改用isinstance兼容逻辑,保持O(1)级查询性能

自行实现MRO遍历查找

isinstance判断的核心逻辑是遍历对象类型的方法解析顺序(MRO),也就是继承链上的所有类,你可以直接复用这个逻辑实现字典查找,遍历的长度只和类的继承层数有关(通常不超过5层),和你注册的类型总数无关,性能接近原生字典查询:

my_func_dict = {
    Foo: foo_func,
    Bar: bar_func,
    FooBar: foobar_func
}

def generic_type_func(my_obj):
    obj_type = type(my_obj)
    # 遍历MRO查找匹配的类,遍历次数固定为继承层级,和注册类型数量无关
    for cls in obj_type.__mro__:
        if cls in my_func_dict:
            my_func = my_func_dict[cls]
            break
    else:
        raise KeyError(f"No matched function for type: {obj_type}")
    my_func()
  • 优点:逻辑完全可控,兼容性强,支持所有符合isinstance规则的对象(包括带spec的Mock对象)。

用标准库functools.singledispatch实现

Python标准库内置的单分发器已经封装了上述的类型分发逻辑,底层基于字典缓存实现,第一次查找后会缓存匹配结果,后续调用都是O(1)性能,代码更简洁易维护:

from functools import singledispatch

@singledispatch
def generic_type_func(my_obj):
    raise KeyError(f"No matched function for type: {type(my_obj)}")

# 注册各类型对应的处理函数
@generic_type_func.register(Foo)
def _(my_obj):
    foo_func()

@generic_type_func.register(Bar)
def _(my_obj):
    bar_func()

@generic_type_func.register(FooBar)
def _(my_obj):
    foobar_func()
  • 优点:无需手动维护类型字典和查找逻辑,标准库实现稳定可靠,天然支持继承、重载等高级特性。

内容的提问来源于stack exchange,提问作者Stanfrancisco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 02:36:04