Python之抽象基类建议收藏

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

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

Python之抽象基类建议收藏此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“”,获取验证码。在微信里搜索“”或者“”或者微信扫描右侧二维码都可以关注本站微信公众号。

抽象基类的核心定义在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提供的常用抽象基类,若要了解各抽象基类的相关信息,请参考具体的文档

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

发表回复

您的电子邮箱地址不会被公开。

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