抽象类经常被描述为"不能实例化的类"。这个定义本身没错--在实现层次上。但局限性太大了。在概念层次上定义抽象类会更有帮助。在概念层次(实现抽象类所代表的概念),抽象类就是其他类的占位符。
也就是说,抽象类为我们提供了一种方法,能够给一组相关的类赋予一个名字。这使我们能够将这一组相关类看成一个概念。
可以使用抽象类定义其派生类必须实现的方法。抽象类还可以包含所有派生类都能够使用的公共方法。派生类是便用抽象类的默认行为还是使用自已有所变化的使为,由派生类自已决定,即对象自已负责自已。
自python2.6版起,引入了抽象类,通过metaclass=abc.ABCMeta来实现抽象定的定义。
即然抽象类是占位符,那么结合pthon3的方法签名,可以为随后其具体化提供进一步帮助。
格式,定义抽象类Server,包含两个属性(host,port),一个方法(startup)。
#!/usr/bin/env python3
import abc
class Server(metaclass = abc.ABCMeta):
def __init__(self, host:str = 'localhost', port:int = 8080):
self.__host = host
self.__port = port
@abc.abstractproperty
def host(self)->str:
return self.__host
@abc.abstractproperty
def port(self)->int:
return self.__port
@abc.abstractmethod
def startup(self, handler:object):
''' startup server handler'''
pass
测试抽象类,占位符作用(即不能被实例化)
>>> Server()
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
Server()
TypeError: Can't instantiate abstract class Server with abstract methods host, port, startup
知识点:python的抽象类的属性和方法是通过abc模块函数abc.abstractpropety,和abc.abstractmethod,来实现的,需要注意的是abc.abstractpropety和python2.6起用的新类propety装饰符使用方法类似。以上例子定义的属性是只读属性。
下面我们来具体化一个Server抽象类,具体化即是实现抽象类所定义的属性和方法。
class WSGIRefServer(Server):
''' WSGIRefServer concrete class Server'''
def __init__(self, host:str = 'localhost', port:int = 8080):
self.__host = host
self.__port = port
def __get_host(self)->str:
return self.__host
def __set_host(self, host:str)->str:
self.__host = host
return self.__get_host()
def __get_port(self)->int:
return self.__port
def __set_port(self, port:int)->int:
self.__port = port
return self.__get_port()
def startup(self, handler:object):
''' startup server handler'''
from wsgiref.simple_server import make_server
serve = make_server(self.__host, self.__port, handler)
serve.serve_forever()
host = property(__get_host, __set_host, doc='host:str = "localhost" ip addr or host name')
port = property(__get_port, __set_port, doc='port:int = 8080 listen port')
具体化抽象类,即必须定现抽象类所定义的全部抽象方法和抽象属性,具体化的同时可以继承抽象类的公用方法,也可以增加自已的新方法,新属生。
怎样继承抽象类的公用方法,可以在抽象类中用classmethod装饰符来装饰一个方法为会用方法。
测试抽象类的具体化类:
>>> assert(issubclass(CGIServer, Server))
>>> assert(isinstance(CGIServer(), Server))
具体化类实列的属性读写测试:
>>> s = CGIServer()
>>> s.host
'localhost'
>>> s.host = '127.0.0.1'
>>> s.host
'127.0.0.1'
知识点:python3的abc,所定义的只读abstractpropety,可以在具体化是实现读,写,删。可能这是个小小的BUG。python的abc,是不能具体化类的.__call__方法的,这一点可以看abc的源码。