__instancecheck__是定义在元类中的类方法,用于自定义isinstance()的行为:当调用isinstance(obj, cls)时,若cls的元类实现了__instancecheck__,Python便跳过默认继承链检查,转而调用该方法返回布尔值决定结果。

__instancecheck__ 是什么,它在 isinstance 中起什么作用?
<strong>instancecheck</strong> 是一个类方法(必须定义在元类中),Python 在调用 isinstance(obj, cls) 时,如果 cls 的元类实现了 <strong>instancecheck</strong>,就会跳过默认的继承链检查,转而调用这个方法来判断 obj 是否“算作” cls 的实例。
注意:它不是定义在普通类里的实例方法,也不是 <strong>class</strong> 或 <strong>mro</strong> 那种自动生效的机制——你得显式提供一个元类,并在里面重写它。
常见错误现象:
- 把 __instancecheck__ 直接写在业务类里,结果完全不触发;
- 返回值不是布尔类型(比如忘了 return True/False),导致 isinstance 报 TypeError;
- 忘了给元类加 __instancecheck__ 的 @classmethod 装饰器,引发 TypeError: __instancecheck__() missing 1 required positional argument: 'instance'。
如何正确实现一个支持自定义 isinstance 的元类?
定义元类时,必须继承 type,并在其中以 @classmethod 方式实现 <strong>instancecheck</strong>。该方法接收两个参数:cls(被检查的类)和 instance(待判断的对象)。
class FlexibleCheck(type):
def __instancecheck__(cls, instance):
# 这里写你的逻辑:比如检查 instance 是否有某个属性、是否满足某协议
if hasattr(instance, 'data') and isinstance(instance.data, dict):
return True
if getattr(instance, '__dict__', None) and 'id' in instance.__dict__:
return True
return False
<p>class MyProtocol(metaclass=FlexibleCheck):
pass</p><h1>测试</h1><p>class A:
def <strong>init</strong>(self):
self.data = {'x': 1}</p><p>class B:
def <strong>init</strong>(self):
self.id = 42</p><p>print(isinstance(A(), MyProtocol)) # True
print(isinstance(B(), MyProtocol)) # True
print(isinstance([], MyProtocol)) # False</p>关键点:
- 元类必须继承 type;
- __instancecheck__ 必须是 @classmethod;
- 不要试图在 MyProtocol 类体里定义它——那会被忽略;
- 返回值严格为 True 或 False,不能是 truthy/falsy 值(如字典、列表)。
为什么不用 __subclasscheck__?它和 __instancecheck__ 有什么区别?
<strong>subclasscheck</strong> 控制的是 issubclass(sub, cls) 的行为,和 isinstance 无关。虽然两者常成对出现(比如实现抽象基类协议),但如果你只改 <strong>subclasscheck</strong>,isinstance 依然走默认逻辑。
立即学习“Python免费学习笔记(深入)”;
典型误用场景:
- 想让 isinstance(x, MyInterface) 成立,却只在元类里写了 __subclasscheck__;
- 把两者逻辑写反:比如在 __instancecheck__ 里去检查 instance.__class__ 是否是子类,这绕过了设计本意,也容易引发递归调用;
- 和 abc.ABCMeta 混用时没注意优先级:若同时继承 ABCMeta 和自定义元类,需用 type(ABCMeta.__name__, (ABCMeta, type), {...}) 手动合并,否则后者会被覆盖。
实际项目中哪些地方会用到它?要注意什么性能问题?
真实使用场景集中在协议模拟、运行时鸭子类型判定、或兼容旧代码的松散类型检查(比如把某些 dict-like 对象“假装”成某个类的实例)。
但要注意:
- 每次调用 isinstance 都会执行你的逻辑,如果里面做了 I/O、复杂遍历或反射操作,开销会明显上升;
- 它不参与 MRO 解析,也不影响继承关系本身,只是“骗过”类型检查——静态类型检查器(如 mypy)完全无视它;
- 如果逻辑依赖对象状态(比如 obj.is_valid),而该状态可能变化,isinstance 的结果就不再是稳定的,容易引发难以追踪的 bug;
- 多数情况下,用 hasattr + 显式判断更清晰,__instancecheck__ 属于“需要解释才能看懂”的隐式机制,团队协作中慎用。
真正难的不是写对语法,而是想清楚:你到底是要做类型检查,还是在掩盖设计缺陷。


















