python中一个类是另一个类的子类的三种情形

1)定义时指定

      class A:pass

      class B(A):pass

   2) 鸭子类型

      python里面大量使用了鸭子类型。所谓鸭子类型,是指从行为特征上去分析一个类的类型,不需要显式得继承一个类型,有句话这么说的,当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。也就是在python里面有一个约定,如果一个类实现了另一个类里的特殊方法(形如__len__),这个类就是另一个类的子类。

      举例来说明,类Sized实现了一个特殊方法__len__,我们定义一个类B,它也实现了__len__,那么类B是类Sized的子类。

     class Sized(metaclass=ABCMeta):

        __slots__ = ()

        @abstractmethod

        def __len__(self):

            return 0

        @classmethod

        def __subclasshook__(cls, C):

            if cls is Sized:

                if any("__len__" in B.__dict__ for B in C.__mro__):

                    return True

            return NotImplemented

        当我们调用issubclas判断类B是不是Sized的子类的时候,它会调用__subclasshook__进行行为分析(是否实现了__len__方法)来判断类B是否是Sized的子类。

   3)虚拟子类

      python还允许指定一个类是另一个类的虚拟子类。指定一个类是另一个类的虚拟子类,通过调用另一个类的类方法register,这个方法在类的元类ABCMeta里面定义,也就是要求另一个类必须指定它的元类是ABCMeta才行。

class ABCMeta(type):

       _abc_invalidation_counter = 0

       def __new__(mcls, name, bases, namespace):

             cls = super().__new__(mcls, name, bases, namespace)

             # Compute set of abstract method names

             abstracts = {name

                   for name, value in namespace.items()

                   if getattr(value, "__isabstractmethod__", False)}

             for base in bases:

                   for name in getattr(base, "__abstractmethods__", set()):

                       value = getattr(cls, name, None)

                       if getattr(value, "__isabstractmethod__", False):

                           abstracts.add(name)

             cls.__abstractmethods__ = frozenset(abstracts)

             # Set up inheritance registry

             cls._abc_registry = WeakSet()

             cls._abc_cache = WeakSet()

             cls._abc_negative_cache = WeakSet()

             cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter

             return cls

      def register(cls, subclass):

       """Register a virtual subclass of an ABC.

        Returns the subclass, to allow usage as a class decorator.

        """

           if not isinstance(subclass, type):

               raise TypeError("Can only register classes")

           if issubclass(subclass, cls):

               return subclass  # Already a subclass

            # Subtle: test for cycles *after* testing for "already a subclass";

            # this means we allow X.register(X) and interpret it as a no-op.

           if issubclass(cls, subclass):

               # This would create a cycle, which is bad for the algorithm below

               raise RuntimeError("Refusing to create an inheritance cycle")

           cls._abc_registry.add(subclass)

           ABCMeta._abc_invalidation_counter += 1  # Invalidate negative cache

           return subclass

   def __subclasscheck__(cls, subclass):

          """Override for issubclass(subclass, cls)."""

           # Check cache

           if subclass in cls._abc_cache:

               return True

           # Check negative cache; may have to invalidate

           if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:

                # Invalidate the negative cache

                cls._abc_negative_cache = WeakSet()

                cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter

           elif subclass in cls._abc_negative_cache:

                return False

           # Check the subclass hook

           ok = cls.__subclasshook__(subclass)

           if ok is not NotImplemented:

                assert isinstance(ok, bool)

                if ok:

                    cls._abc_cache.add(subclass)

                else:

                    cls._abc_negative_cache.add(subclass)

                return ok

           # Check if it's a direct subclass

           if cls in getattr(subclass, '__mro__', ()):

                cls._abc_cache.add(subclass)

                return True

            # Check if it's a subclass of a registered class (recursive)

            for rcls in cls._abc_registry:

                if issubclass(subclass, rcls):

                    cls._abc_cache.add(subclass)

                    return True

           # Check if it's a subclass of a subclass (recursive)

           for scls in cls.__subclasses__():

                if issubclass(subclass, scls):

                    cls._abc_cache.add(subclass)

                    return True

           # No dice; update negative cache

           cls._abc_negative_cache.add(subclass)

           return False

   从这里的代码实现,也给了我们一个启发,如果要定义一个多个类通用的类方法,就把这个方法定义到这些类的共同的元类当中。注册一个类为另一个类的虚拟子类,通过调用另一个类的register方法,check的时候issubclass调用另一个类的__subclasscheck__,里面的逻辑一目了然,有兴趣的读者可以自行阅读。

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__空无一人__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值