python之abc和six

2017-04-18  本文已影响4461人  俊杰的笔记

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的类必须全部实现其抽象方法,否则实例化会报错。

简单总结:

  1. 用法:
  1. 通过标准方式继承抽象类的类,必须全部实现抽象类的抽象方法,否则不能实例化
  2. 虚拟子类不影响subclasses, 可以不实现抽象方法,只要不调用。
上一篇下一篇

猜你喜欢

热点阅读