当前位置: 首页 > 工具软件 > Python Six > 使用案例 >

python之abc和six

计光赫
2023-12-01

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. 用法:
  • @six.add_metaclass(abc.ABCMeta)用于指定元类,兼容python2和3
  • @abc.abstractmethod用于声明抽象方法;
  • abc.ABCMeta.register方法用于将任意类注册为虚拟子类
  1. 通过标准方式继承抽象类的类,必须全部实现抽象类的抽象方法,否则不能实例化
  2. 虚拟子类不影响subclasses, 可以不实现抽象方法,只要不调用。



作者:俊杰的简书
链接:https://www.jianshu.com/p/d9cd26c06f4b
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 类似资料: