python中的隐式继承

先看一个例子

from typing import Sized

class MyLen:
    def __len__(self):
        return 10


print(issubclass(MyLen, Sized))
print(MyLen.__mro__)

输出为True,但是我们没有显示继承Sized类,打印__mro__,同样没有Sized类。这是因为在python中可以通过实现一些协议、方法来隐式继承类型。
如果实现了__getitem__魔法方法,自定义对象就能称为”序列类型”,可以使用类似list序列那样的操作。python还定义了基础类型的协议,例如:

Hashable = _alias(collections.abc.Hashable, 0)  # Not generic.
Awaitable = _alias(collections.abc.Awaitable, 1)
Coroutine = _alias(collections.abc.Coroutine, 3)
AsyncIterable = _alias(collections.abc.AsyncIterable, 1)
AsyncIterator = _alias(collections.abc.AsyncIterator, 1)

只要实现了指定魔法方法,无需显示继承,也可以让我们的类是Awaitable的。

我们可以自定义一套类型体系来实现隐式继承。这需要metaclass__subclasshook__等技术的辅助。

class MyBase(metaclass=ABCMeta):
    @classmethod
    def __subclasshook__(cls, C):
        if cls is MyBase:
            if any("my_method" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented


class ImplementsMethod:
    def my_method(self):
        pass


class DoesNotImplementMethod:
    pass


print(issubclass(ImplementsMethod, MyBase))  # 输出: True
print(issubclass(DoesNotImplementMethod, MyBase))  # 输出: False

现在只要有一个类拥有my_method方法,就可以通过issubclass方法的判断,相当于可以自定义协议。

此外还有两个魔法方法__subclasscheck____instancecheck__,用来判断是否是一个类的子类或是实例。


class Test(metaclass=ABCMeta):
    @classmethod
    def __subclasscheck__(cls, subclass):
        print("__subclasscheck__", cls, subclass)
        if 'my_method' in subclass.__dict__:
            return True
        return False


print(issubclass(ImplementsMethod, Test))

输出依然为False,并且Test的类的__subclasscheck__方法并没有被调用。这两个方法需要被定义在元类中才可以生效。

class MyMeta(type):
    def __instancecheck__(cls, instance):
        print("__instancecheck__", cls, instance)
        return True

    def __subclasscheck__(cls, subclass):
        print("__subclasscheck__", cls, subclass)
        if 'my_method' in subclass.__dict__:
            return True
        return False


class Test(metaclass=MyMeta):
    pass

print(issubclass(ImplementsMethod,
                 Test))  # True __subclasscheck__ <class '__main__.Test'> <class '__main__.ImplementsMethod'>
print(isinstance(ImplementsMethod, Test))  # True

posted @ 2024-12-26 18:42  LRJ313  阅读(42)  评论(0)    收藏  举报