一,老样子,抛出一个问题:我们想定义一个类作为接口或者是抽象基类,如何在此之上执行类型检查并确保子类中实行特定的规范!
要定义抽象基类:可以考虑使用abc模块:
from abc import ABCMeta, abstractmethod class Mystream(metaclass=ABCMeta) # 必须要继承 @abstractmethod def read(self, maxbytes=-1): pass @abstractmethod def write(self, data): pass
抽象基类的核心特征就是不能直接实例化。如果尝试这么做的话,错误提示:
a = Mystream() # TypeError: can't instantiate abstract class # Mystream with abstract methods read, write
抽象基类是用来给其他类当做基类来使用的,这些子类需要实现积累中的那些方法。示例如下:
class Stream(Mystream): def read(self, maxbytes=-1): pass def write(self, data): pass
划重点来了!
假如子类中没有read或者write方法,那么直接报错!
抽象基类的主要用途是强制规定所需的编程接口。例如:一种看待Mystream基类的方式就是在高层次上指定一个接口规范,使其准许读取和写入数据。显式检查这个接口的代码可以写成如下状态。
def Mycheck(obj, stream): if not isinstance(stream, Mystream): raise TypeError('Expected an Mystream') ……
我们可能会认为这种形式的类型检查只有在子类化抽象基类(ABC)时才能工作,但是抽象基类也容许其他的类向其注册,然后实现所需的接口。例如我们可以这样做:
import io Mystream.register(io.IOBase) # 随意打开一个普通文件进行类型检查 f = open('foo.txt') isinstance(f, Mystream) # return True
应该提到的是,@abstractmethod也同样可以施加到静态方法、类方法和@property属性上,但是!!!!!一定要注意顺序!!!
@abstractmethod必须紧挨着函数定义!!
示例如下:
from abc import ABCMtea, abstractmethod class A(metaclass=ABCMeta): @property @abstractmethod def name(self): pass @classmethod @abstractmethod def method(cls): pass @staticmethod @abstractmethod def method2(): pass @name.setter @abstractmethod def name(self, value): pass