Python进阶:Python进阶:理解元类创建类ABCMeta
- 一、理解元类(Meta class)
- 1.1 元类直观理解
- 1.2 Python官方文档给出的元类描述
- 二、理解抽象基类(ABC, Abstract Base Classes)
- 2.1 Python官方文档给出的抽象基类概念
- 2.2 抽象基类abc模块源码注释理解
- 三、理解ABCMeta
- 3.1 理解ABCMeta
- 3.2 创建ABCMeta类的过程
一、理解元类(Meta class)
要想理解ABCMeta类,我们需要先理解元类。
1.1 元类直观理解
理解元类:
(1)元类的含义:Meta类就是元类——类的类,在Python中定义类的关键字class
也是一个对象,那么实例化class
对象的类就是元类。元类的目的就是为了控制类的创建行为。
(2)元类的生成:type
作为Python的内建元类,是用来控制类的生成的,class
对象就是type
实例化生成的。
(3)Python中类的创建方法:因此,Python中创建类的方法其实有两种:(a)使用class
关键字;(2)通过type
关键字
1.2 Python官方文档给出的元类描述
有了上面的直观理解,再来看看Python中文官网文档的第3节的数据类型:3.3.3.1元类中对元类的表述:
metaclass
元类:一种用于创建类的类。类定义包含类名、类字典和基类列表。元类负责接受上述三个参数并创建相应的类。大部分面向对象的编程语言都提供一个默认实现。Python的特别之处在于可以创建自定义元类。大部分用户永远不需要这个工具,但当需要出现时,元类可提供求强而优雅的解决方案。它们已被用于记录属性访问日至、添加线程安全性、跟踪对象创建、实现单例,以及其他很多任务。
默认情况下,Python的类是使用type()
来构建的。类体将在一个新的命令空间内执行,类名会被局部绑定到type(name, bases, namespace)
的结果。
类创建过程可通过在定义行传入metaclass
关键字参数,或通过继承一个包含此参数的现有类来进行定制。在以下示例中,MyClass
和MySubclass
都是Meta
的实例:
二、理解抽象基类(ABC, Abstract Base Classes)
2.1 Python官方文档给出的抽象基类概念
Python中文手册中的手册术语对照表中对抽象基类的表述如下:
abstract base class – 抽象基类:抽象基类简称ABC,是对duck-typing(鸭子类型)的补充,它提供了一种定义接口的新方式,相比之下其他及其例如hasattr()
显得过于笨拙或有微妙错误(例如使用魔法方法)。ACB
引入了虚拟子类,这种类并非继承子其他类,但却能被isinstance()
和issubclass()
所认可。Python自带许多内置的ABC用于实现数据结构(在collections.abc
模块中)、数字(在numbers
模块中)、流(在io
模块中)、导入查找其和加载器(在importlib.abc
模块中)。
由于下面在查看
ABCMeta
源码中的注释及示例时,用到isinstance()
和issubclass()
两个函数,这里解释以下它们的作用:
- (1)
isinstance(object, classinfo)
:如果object
参数是classinfo
参数的实例,或其(直接、间接或virtual)子类的实例,则返回True
;否则返回False
。- (2)
issubclass(class, classinfo)
:如果class
是classinfo
(或其直接、间接或virtual)的子类,则返回True
;否则返回False
。
2.2 抽象基类abc模块源码注释理解
Python库包中的abc
定义了抽象基类(ABC, Abstract Base Classes)的组件。abc
模块提供了一个抽象基类元类(ABCMeta
),用来定义抽象类。同时提供了一个工具类ABC
,可以用它以继承的方式定义抽象基类。由下图的abc
模块的组成结构图,可以看出ABCMeta
类的数据类型为type
类型,可以用来生成ABC
类(其类型为ABCMeta
类型)。
abc.ABC
类
abc.ABC
是一个使用ABCMeta
作为元类的工具类。抽象基类可以通过ABC
派生来简单地创建:
注意,ABC
的类型仍然是ABCMeta
。简单来说,abc
模块、ABCMeta
类、ABC
类关系如下图所示:
三、理解ABCMeta
3.1 理解ABCMeta
有了元类、抽象基类两个概念的感性认识,这个时候就容易理解ABCMeta了。
abc.ABCMeta
是用来定义抽象基类ABC
的元类。使用ABCMeta
元类创建抽象基类,并可以像mix-in
类一样直接被子类继承。同时,我们也可以将不相关的具体类(包括内建类)和抽象基类注册为“抽象子类”——这些类以及它们的子类会被内建函数issubclass()
识别为对应的抽象基类的子类,但是该抽象基类不会出现在其MRO
(Method Resolution
Order,方法解析顺序)中,抽象基类中实现的方法也不可调用(即使通过super()
调用也不行)。
3.2 创建ABCMeta类的过程
使用ABCMeta元类创建的类可以使用register(subclass)
方法,register(subclass)
将“子类”注册为该抽象基类的“抽象子类”,比如下面的例子: