python模块--abc

1. 抽象类

python中没有接口的概念,但是提供了abc模块来实现接口的目的,其实接口就是一个 规范,定义了一些抽象方法,但是没有具体实现,具体的实现交给继承它的类,如果一个类继承了抽象类,但是没有完全实现父类的抽象方法,就不能实例化对象。

在其他语言比如java go中,没有实现全接口的抽象方法,编译都会报错,但是python里只要不进行实例化,不会报错,毕竟python是一种解释性语言,不是编译型的。

如果说类是抽象对象的共同属性和方法,那么抽象类或接口就是 将 具体类的一些共性给抽象出来的 规范.

2. 类的__abstractmethods__魔法属性

如果一个类的__abstractmethods__属性不为空,那么它就不能实例化

class AbstractClass:
	pass
AbstractClass.__abstractmethods__ = set(['my_abstract__method'])

AbstractClass()

`TypeError: Can't instantiate abstract class AbstractClass with abstract methods my_abstract__method`

3. abstractmethod方法和ABCMeta类

直接看源码

def abstractmethod(funcobj):
    """A decorator indicating abstract methods.

    Requires that the metaclass is ABCMeta or derived from it.  A
    class that has a metaclass derived from ABCMeta cannot be
    instantiated unless all of its abstract methods are overridden.
    The abstract methods can be called using any of the normal
    'super' call mechanisms.

    Usage:

        class C(metaclass=ABCMeta):
            @abstractmethod
            def my_abstract_method(self, ...):
                ...
    """
    funcobj.__isabstractmethod__ = True
    return funcobj

abstractmethod()方法就是一个装饰器,给被装饰的函数添加一个__isabstractmethod__属性,
如果一个方法的__isabstractmethod__为True,那么它就是抽象方法。

接下来这个ABCMeta类就很核心了,python中的抽象类都是它创建的,因为它就是一个元类,一个创建类的类,如果对元类不了解的话,先去了解一下元类的概念。

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, **kwargs):
        cls = super().__new__(mcls, name, bases, namespace, **kwargs)
        # 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

这个new方法就是给类动态添加__abstractmethods__属性,从代码里可以看出来,它先将自身过滤一遍,自身是否有抽象方法,然后在去找父类中的抽象方法,如果类没有实现父类的抽象方法,就添加到
cls.__abstractmethods__中。

4. 使用

abc模板提供了一个便捷类,供用户的抽象类继承,它就是ABC

from abc import abstractmethod, ABC

class Animal(ABC):
	@abstractmethod
	def walk(self):
		pass

class Dog(Animal):
	def walk(self):
		print('狗走路')

Animal是一个抽象类,Dog类必须实现walk方法,否则不能使用,因为在父类Animal中walk()方式是抽象方法,子类必须实现了该方法,才能实例化。

另外python是允许多重继承的,这样就更灵活了,可以达到java中允许接口多实现的类似功能。

也可以定义个抽象类,指定其元类是ABCMeta,然后定义一系列的抽象方法,这个跟直接继承ABC实现抽象类,其本质都是一样的,因为最终的子类都是会在ABCMeta中new方法中进行改造,就是动态添加__abstractmethods__属性,如果该属性不为空,就不能实例化。

5. python自身的应用

python中的collections包中也有一个abc模块,这个模块导入了_collections_abc模块,_collections_abc这个模块,定义了许多python许多原生抽象类,它们都指定ABCMeta为元类,有兴趣的可以去看看。

猜你喜欢

转载自blog.csdn.net/weixin_42237702/article/details/103654757
ABC
今日推荐