python之abc和six
abc是Abstract Base Classes的缩写
six的元类注解兼容python2和3
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class PluginBase(object):
@abc.abstractmethod
def func_a(self, data):
"""
an abstract method need to be implemented.
:param data:
:return:
"""
@abc.abstractmethod
def func_b(self, output, data):
"""
another abstract method need to be implemented.
:param output:
:param data:
:return:
"""
class RegisteredImplementation(object):
def func_c(self, data):
print "Method in third-party class, " + str(data)
PluginBase和RegisteredImplementation在语法上没有任何继承关系。
但PluginBase的元类是abc.ABCMeta
PluginBase本身是由ABCMeta创建出来的。ABCMeta作为元类,其方法的第一个参数是cls, 代表元类的实例,即指定元类为ABCMeta的类,也就是PluginBase
在ABCMeta中有个register方法:
def register(cls, subclass):
"""Register a virtual subclass of an ABC."""
# ...
PluginBase可以直接调用register,就像实例调用实例方法一样,点操作符前面是“接收者”: PluginBase.register(RegisteredImplementation)
等同于: abc.ABCMeta.register(PluginBase, RegisteredImplementation)
那么这个方法是干什么的?从源码可以看出,是将一个类注册为这个类的虚拟子类。
实验一下:
if __name__ == '__main__':
# OOP=> PluginBase.register(RegisteredImplementation)
abc.ABCMeta.register(PluginBase, RegisteredImplementation)
for sc in PluginBase.__subclasses__():
print "subclass of PluginBase: " + sc.__name__
print "----------"
print issubclass(RegisteredImplementation, PluginBase)
print isinstance(RegisteredImplementation(), PluginBase)
print "----------"
obj1 = RegisteredImplementation()
obj1.func_c("")
# 报错,AttributeError: 'RegisteredImplementation' object has no attribute 'func_a'
obj1.func_a("asdf")
首先将RegisteredImplementation注册为PluginBase的虚拟子类;
然后查看PluginBase的subclasses, 结果什么也没打出。说明虚拟子类不是真正的子类。
再查看issubclass和isinstance方法,均打印True. 说明虚拟子类影响这两个判断方法
最后尝试用RegisteredImplementation的实例调用自身和PluginBase的方法,结果调用自身的方法OK,调用PluginBase的抽象方法报错了。
虚拟子类就到这里。下面看下,如果一个类继承了PluginBase会怎样
PluginBase指定了元类,且声明了两个抽象方法。
class RealSubclass(PluginBase):
def func_a(self, data):
print "impl"
def func_x(self):
print "func_x"
if __name__ == '__main__':
# TypeError: Can't instantiate abstract class RealSubclass with abstract methods func_b
x = RealSubclass()
由此可见,PluginBase利用six和abc的注解充当了Java中interface的角色
继承PluginBase的类必须全部实现其抽象方法,否则实例化会报错。
简单总结:
- 用法:
- @six.add_metaclass(abc.ABCMeta)用于指定元类,兼容python2和3
- @abc.abstractmethod用于声明抽象方法;
- abc.ABCMeta.register方法用于将任意类注册为虚拟子类
- 通过标准方式继承抽象类的类,必须全部实现抽象类的抽象方法,否则不能实例化
- 虚拟子类不影响subclasses, 可以不实现抽象方法,只要不调用。