Python之抽象基类建议收藏

抽象基类的核心定义在abc模块中,模块中包括了创建抽象基类需要的修饰符和元类型abc.ABCMeta用来生成抽象基础类的元类。由它生成的类可以被直接继承。abc.ABC辅助类,让你可以不用关心元类

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

全栈程序员社区此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“验证码”,获取验证码。在微信里搜索“全栈程序员社区”或者“www_javaforall_cn”或者微信扫描右侧二维码都可以关注本站微信公众号。

抽象基类的核心定义在abc模块中,模块中包括了创建抽象基类需要的修饰符和元类型
abc.ABCMeta

  用来生成抽象基础类的元类。由它生成的类可以被直接继承。
abc.ABC

  辅助类,让你可以不用关心元类概念,直接继承它,就有了ABCMeta元类。使用时注意元类冲突
@abc.abstractmethod

  定义抽象方法,除了这个装饰器,其余装饰器都被deprecated了

1. 抽象类示例 

from abc import ABCMeta,abstractmethod

class Animal(metaclass = ABCMeta):  
    test = "hello world"
    
    def __init__(self):
        self.food = None
        
    @abstractmethod
    def eat(self):
        pass

    @abstractmethod
    def run(self):
        pass

    @classmethod
    def __subclasshook__(cls, subclass):   #重写__subclasshook__方法,判断是否为子类
        print ("come in")
        if cls is Animal:
            if any("eat" in b.__dict__ for b in subclass.__mro__):
                return True
        return NotImplemented   

  以上为Animal的抽象基类,注意重写了__subclasscheck__(cls, subclass)方法来改变issubclass或者isinstance的行为,__subclasscheck__(cls, subclass)必须为@classmethod

2. 具体化抽象类的两种方式

  具体化抽象类可以有两种方式,一种通过注册(register),另外一种通过继承。

register方法 

class Monkey:
    def __init__(self):
     #不会出现在类的__mro__,所以不会通过super()方法调用基类方法 super().
__init__() self.food= "banana" def eat(self): print ("{0} eat {1}".format(self.__class__.__name__, self.food))
  #没有实现抽象方法时,实例化的时候不会报错,只有在调用的时候才会报错 #
def run(self): #pass if __name__ == "__main__": Animal.register(Monkey)
    print (issubclass(Animal,Monkey))
    m = Monkey()
    m.eat()

 >>>> come in
>>>> True
>>>> Monkey eat banana
>>>> (<class ‘__main__.Monkey’>, <class ‘object’>)

注册方式的缺点:不会出现在类的
MRO (Method Resolution Order),故而也不能通过
super()来调用抽象方法。当没有实现抽象方法时,实例化时候不会报错,只有在调用时候才会报错。

继承方法

  直接从抽象基类派生子类有一个好处,除非子类实现抽象基类的抽象方法,否则子类不能实例化。 

class Monkey(Animal):
    def __init__(self):
        super().__init__()
        self.food= "banana"
        
    def eat(self):
        print ("{0} eat {1}".format(self.__class__.__name__, self.food))

    def run(self):
        pass
        
if __name__ == "__main__":
    Animal.register(Monkey)
    print (issubclass(Animal,Monkey)))
    m = Monkey()
    m.eat()
    print (Monkey.__mro__)

3. ABCMeta类和ABC类源码

class ABCMeta(type):

    """Metaclass for defining Abstract Base Classes (ABCs).

    Use this metaclass to create an ABC.  An ABC can be subclassed
    directly, and then acts as a mix-in class.  You can also register
    unrelated concrete classes (even built-in classes) and unrelated
    ABCs as 'virtual subclasses' -- these and their descendants will
    be considered subclasses of the registering ABC by the built-in
    issubclass() function, but the registering ABC won't show up in
    their MRO (Method Resolution Order) nor will method
    implementations defined by the registering ABC be callable (not
    even via super()).

    """

    # A global counter that is incremented each time a class is
    # registered as a virtual subclass of anything.  It forces the
    # negative cache to be cleared before its next use.
    # Note: this counter is private. Use `abc.get_cache_token()` for
    #       external code.
    _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 _dump_registry(cls, file=None):
        """Debug helper to print the ABC registry."""
        print("Class: %s.%s" % (cls.__module__, cls.__qualname__), file=file)
        print("Inv.counter: %s" % ABCMeta._abc_invalidation_counter, file=file)
        for name in sorted(cls.__dict__.keys()):
            if name.startswith("_abc_"):
                value = getattr(cls, name)
                print("%s: %r" % (name, value), file=file)

    def __instancecheck__(cls, instance):
        """Override for isinstance(instance, cls)."""
        # Inline the cache checking
        subclass = instance.__class__
        if subclass in cls._abc_cache:
            return True
        subtype = type(instance)
        if subtype is subclass:
            if (cls._abc_negative_cache_version ==
                ABCMeta._abc_invalidation_counter and
                subclass in cls._abc_negative_cache):
                return False
            # Fall back to the subclass check.
            return cls.__subclasscheck__(subclass)
        return any(cls.__subclasscheck__(c) for c in {subclass, subtype})

    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


class ABC(metaclass=ABCMeta):
    """Helper class that provides a standard way to create an ABC using
    inheritance.
    """
    pass        

4.Python中的抽象基类

  collections.abc.Callable

  collections.abc.Iterator

  collections.abc.Mapping

  numbers

  以上为Python提供的常用抽象基类,若要了解各抽象基类的相关信息,请参考具体的文档

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120189.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • java中Scanner类用法的详解[通俗易懂]

    java中Scanner类用法的详解[通俗易懂] 一  java.util.Scanner是Java5的新特征,我们可以通过Scanner类来获取用户的输入。首先要导入包  import java.util.Scanner;Scanner类的创建对象:   Scanner S=newScanner(System.in);   方法基本格式  hasNextXxx()  判断是否还有下一个输入项,其中Xxx可以是Int,…

    2022年7月7日
  • 计算机网络协议(三)——UDP、TCP、Socket[通俗易懂]

    计算机网络协议(三)——UDP、TCP、Socket[通俗易懂]底层网络知识详解:最重要的传输层概述一、UDP协议二、TCP协议2.1TCP的三次握手概述这个专栏的计算机网络协议,我是在极客时间上学习已经有三万多人购买的刘超老师的趣谈网络协议专栏,讲的特别好,像看小说一样学习到了平时很枯燥的知识点,计算机网络的书籍太枯燥,感兴趣的同学可以去付费购买,绝对物超所值,本文就是对自己学习专栏的总结,评论区可以留下你的问题,咱们一起讨论!传输层中有两…

    2022年6月7日
  • 比特币挖矿培训来到印度30个城市[通俗易懂]

    比特币挖矿培训来到印度30个城市[通俗易懂]点击上方“蓝色字”可关注我们!暴走时评:为了促进印度达利特阶层的商业企业发展,2005年印度成立了行业协会DICCI。Mahabfic则是在马哈拉施特拉邦宣传区块链、金融科技、ICO和加密货币投资的平台。最近两个机构合作在印度30个城市展开比特币挖矿培训,包括区块链技术、挖矿、创业、初创企业等课程内容。旨在为这些地区年轻人自主就业提供帮助,为这些地区创造新的经济增长点。作者:KevinHelms

    2022年5月28日
  • 手机号码正则表达式匹配

    手机号码正则表达式匹配正则表达式匹配手机号码最近在学习正则表达式,在这里写一个手机号码的匹配表达式手机号码的规则11位,第一位一定是1 第二位和第三位根据不同运营商的号码段有所区别,只有有限的组合是合法的手机号码 后8位可以是任意数字表达式^1(3[0-9]|5[0-3,5-9]|7[1-3,5-8]|8[0-9])\d{8}$解释:^:代表起始,即手机号码只能以1为开头3[0-9]:代表手机号码第二位可以是3,第三位可以是0-9中任意一个数字5[0-3,5-9]:代表手机号码第二位也可以是5,

    2022年5月12日
  • IJ快捷键

    IJ快捷键ctrl+shift+alt:多行操作psvm:生成main()方法;fori:生成for循环;Ctrl+Alt+v:自动补齐返回值类型ctrl+o:覆写方法ctrl+i:实现接口中的方法ctrl+shift+u:大小写转换CTRL+SHIFT+Z:取消撤销Alt+Insert:生成构造方法、getter、setterctrl+y:删除当前行Ctrl+Shift+J:将选中的行合并成一行ctrl+g:定位到某一行Ctrl+Shitft+向下箭头:将光标所在的代码块向下整体移动Ct.

    2022年6月27日
  • Idea激活码永久有效Idea2019.3.5激活码教程-持续更新,一步到位

    Idea激活码永久有效Idea2019.3.5激活码教程-持续更新,一步到位Idea激活码永久有效2019.3.5激活码教程-Windows版永久激活-持续更新,Idea激活码2019.3.5成功激活

    2022年6月17日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号