今天在看apscheduler源代码中,看到abc.py这个文件,出于好奇,深入看了一下。
abc的缩写是Abstract Base Classes,翻译就是抽象基类。详细链接可以查看此处
可以看出这个是类是2007年,由Python创始人Guido van Rossum和Talin一起引入的。
引入目的:
首先我们看功能一:
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]