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

  • 相关阅读:
    进阶篇:3.1.1.3)DFM注塑-机械紧固
    进阶篇:3.1.1.2)DFM注塑-卡扣
    进阶篇:5.3)装配偏移
    基础篇:6.9)形位公差-检测方法Measurement
    高阶篇:4.1)QFD质量功能展开-总章
    基础篇:6.3)形位公差-要素 Feature
    基础篇:6.8)形位公差-公差带 Tolerance Zone
    感想篇:9)关于结构工程师的一种打开方式
    知识点篇:5)产品结构设计工程师的定义、职责及技能要求
    [洛谷P3386][题解][模板]二分图匹配
  • 原文地址:https://www.cnblogs.com/xiaobingqianrui/p/8600394.html
Copyright © 2020-2023  润新知