Python抽象类(ABC)浅析

 

今天在看apscheduler源代码中,看到abc.py这个文件,出于好奇,深入看了一下。 

abc的缩写是Abstract Base Classes,翻译就是抽象基类。详细链接可以查看此处

Python抽象类(ABC)浅析_第1张图片

可以看出这个是类是2007年,由Python创始人Guido van Rossum和Talin一起引入的。

引入目的:

  • 重载isinstance()和issubclass()。
  • 增加新模块abc,用作“ ABC支持框架”。 它定义了与ABC一起使用的元类和可用于定义抽象方法的装饰器。
  • 增加支持容器和迭代器的具体ABC,并将添加到集合模块中。

首先我们看功能一:

1、重载isinstance和issubclass. 

import  abc

class PluginBase(object):
    __metaclass__ = abc.ABCMeta
    pass

PluginBase.register(tuple)


print(issubclass(tuple, PluginBase))
print(isinstance((), PluginBase))


# python3
class PluginBase1(metaclass=abc.ABCMeta):
    pass

可以看到,通过register可以注册一个子类。

2、实现抽象的方法。

# abc_base.py
import abc

class PluginBase(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def load(self, input):
        """Retrieve data from the input source and return an object."""
        return

    @abc.abstractmethod
    def save(self, output, data):
        """Save the data object to the output."""
        return

# abc_test.py
import abc
from abc_base import PluginBase


class RegisteredImplementation(object):

    def load(self, input):
        return input.read()

    def save(self, output, data):
        return output.write(data)


PluginBase.register(RegisteredImplementation)

if __name__ == '__main__':
    # Raise Exception
    # PluginBase()
    # TypeError: Can't instantiate abstract class PluginBase with abstract methods load, save

    print 'Subclass:', issubclass(RegisteredImplementation, PluginBase)
    print 'Instance:', isinstance(RegisteredImplementation(), PluginBase)
    regimpl_instance = RegisteredImplementation()

    #Subclass: True
    #Instance: True
    print(regimpl_instance.load(file("abc_base.py")))

可以测试,不能实例化积累。

3、对容器的支持。

在Python源码 typing.pyi中有下面代码,可以看出来Sized,Hashable里面都有引入ABCMeta

# 部分
class Sized(Protocol, metaclass=ABCMeta):
    @abstractmethod
    def __len__(self) -> int: ...

@runtime
class Hashable(Protocol, metaclass=ABCMeta):
    # TODO: This is special, in that a subclass of a hashable class may not be hashable
    #   (for example, list vs. object). It's not obvious how to represent this. This class
    #   is currently mostly useless for static checking.
    @abstractmethod
    def __hash__(self) -> int: ...

@runtime
class Iterable(Protocol[_T_co]):
    @abstractmethod
    def __iter__(self) -> Iterator[_T_co]: ...

@runtime
class Iterator(Iterable[_T_co], Protocol[_T_co]):
    @abstractmethod
    def next(self) -> _T_co: ...
    def __iter__(self) -> Iterator[_T_co]: ...
import collections

iter = collections.Iterator()

会报错
TypeError: Can't instantiate abstract class Iterator with abstract methods next

我们实现一个斐波拉契数列

import collections
class MyFib(collections.Iterator):
    """
    Extend the abstract base class and create Fib sequence object.
    """
    def __init__(self, max):
        self.max = max
        self.a = 0
        self.b = 1

    def next(self):
        """
        This method from the super class must be implemented.
        :return: the iterator object.
        """
        fib = self.a
        if fib > self.max:
            raise StopIteration
        else:
            self.a, self.b = self.b, self.a + self.b

        return fib


if __name__ == '__main__':
    my_fib = MyFib(10)
    print(issubclass(my_fib, collections.Iterable))
    # Result, True, reason? because the Iterable is base class of Iterator. 
    print(list(my_fib))
    # [0, 1, 1, 2, 3, 5, 8]

 

你可能感兴趣的:(python)