抽象类被 meta class 继承导致其 isinstance 与 issubclass 检查失效

Python 3.10.4 (main, Mar 31 2022, 03:37:37) [Clang 12.0.0 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from abc import ABCMeta
>>> class A(metaclass=ABCMeta): pass
... 
>>> issubclass(int, A)
False
>>> class Meta(type, A): pass
... 
>>> issubclass(str, A)
Traceback (most recent call last):
  File "", line 1, in <module>
  File "/Users/lutingwang/anaconda3/envs/todd/lib/python3.10/abc.py", line 123, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
  File "/Users/lutingwang/anaconda3/envs/todd/lib/python3.10/abc.py", line 123, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
TypeError: unbound method type.__subclasses__() needs an argument

正常来说, issubclass 应该返回 False 。但是在定义了 Meta 之后, issubclass 开始报错。两次调用 issubclass 的对象分别是 intstr ,是为了绕过 issubclass 的缓存机制。

造成这一现象的原因是, issubclass 需要递归遍历 A 的所有子类,这依赖于的 __subclasses__ 方法。通过报错信息不难看出,问题的关键在于 __subclasses__ 被错误调用。因此我们怀疑, Meta.__subclasses__ 导致了报错。为了验证猜想,我们编写了以下测试代码

>>> Meta.__subclasses__()
Traceback (most recent call last):
  File "/Users/lutingwang/Developer/todd/tmp.py", line 13, in <module>
    Meta.__subclasses__()
TypeError: unbound method type.__subclasses__() needs an argument

报错信息一致,说明我们的猜想是正确的。因为 Meta 中没有定义 __subclasses__ 方法,所以在调用 Meta.__subclasses__ 时会自动解析到 type.__subclasses__

>>> Meta.__subclasses__
<method '__subclasses__' of 'type' objects>

但是这里的 Meta.__subclasses__Meta 从基类 type 继承的方法,而不是 meta class type 实现的方法。二者的区别在于,继承而来的方法是未绑定的,而 meta class 实现的方法是绑定的。为了解决这一问题,需要重载 Meta.__subclasses__ ,使之可以处理未绑定的情况。

class Meta(type, A):

    def __subclasses__(self=...) -> List[type]:
        if self is ...:
            return type.__subclasses__(RegistryMeta)
        return super().__subclasses__()

__isinstance__ 底层调用了 __issubclass__ ,因此上述分析同样适用。

你可能感兴趣的:(debug记录,python)