python中并没有提供抽象类与抽象方法,但是提供了内置模块abc(abstract base class)来模拟实现抽象类。
可以通过abc将基类声明为抽象类的方式,然后注册具体类作为这个基类的实现。
定义抽象类
首先在abc_base.py中定义一个抽象基类PluginBase,这个基类用于保存和加载数据。
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.abstractmethod将方法声明为抽象方法。
注册具体类
然后在abc_register.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__':
print 'Subclass:', issubclass(RegisteredImplementation, PluginBase)
print 'Instance:', isinstance(RegisteredImplementation(), PluginBase)
在上面的例子中,RegisteredImplementation并没有继承自PluginBase,而是将其注册为PluginBase的一个实现。
运行结果如下:
Subclass: True
Instance: True
通过派生实现
也可以在abc_subclass.py中直接继承抽象类:
import abc
from abc_base import PluginBase
class SubclassImplementation(PluginBase):
def load(self, input):
return input.read()
def save(self, output, data):
return output.write(data)
if __name__ == '__main__':
print 'Subclass:', issubclass(SubclassImplementation, PluginBase)
print 'Instance:', isinstance(SubclassImplementation(), PluginBase)
这样做有一个副作用,当查询基类的子类时,会输出所有继承自改类的子类。
import abc
from abc_base import PluginBase
import abc_subclass
import abc_register
for sc in PluginBase.__subclasses__():
print sc.__name__
输出结果如下:
SubclassImplementation
不完整的实现
直接从抽象基类派生子类有一个好处,除非子类完全抽象基类的抽象方法,否则子类不能实例化。
import abc
from abc_base import PluginBase
class IncompleteImplementation(PluginBase):
def save(self, output, data):
return output.write(data)
if __name__ == '__main__':
print 'Subclass:', issubclass(IncompleteImplementation, PluginBase)
print 'Instance:', isinstance(IncompleteImplementation(), PluginBase)
ABC中的具体方法
尽管具体子类必须实现抽象类中的所有抽象方法,但是,抽象类中也可以包含具体方法。在子类中可以通过super()来调用。
import abc
from cStringIO import StringIO
class ABCWithConcreteImplementation(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def retrieve_values(self, input):
print 'base class reading data'
return input.read()
class ConcreteOverride(ABCWithConcreteImplementation):
def retrieve_values(self, input):
base_data = super(ConcreteOverride, self).retrieve_values(input)
print 'subclass sorting data'
response = sorted(base_data.splitlines())
return response
input = StringIO("""line one
line two
line three
""")
reader = ConcreteOverride()
print reader.retrieve_values(input)
print
输出结果如下:
base class reading data
subclass sorting data
['line one', 'line three', 'line two']
抽象属性
可以通过@abstractproperty定义抽象属性:
import abc
class Base(object):
__metaclass__ = abc.ABCMeta
@abc.abstractproperty
def value(self):
return 'Should never get here'
class Implementation(Base):
@property
def value(self):
return 'concrete property'
try:
b = Base()
print 'Base.value:', b.value
except Exception, err:
print 'ERROR:', str(err)
i = Implementation()
print 'Implementation.value:', i.value
输出结果如下:
ERROR: Can't instantiate abstract class Base with abstract methods value
Implementation.value: concrete property